Merge branch 'staging' into deprecate-cc-or-instruct
| @@ -1,9 +1,20 @@ | |||
| 1 | > [!IMPORTANT] | 1 | > [!IMPORTANT] |
| 2 | > ここに掲載されている情報は、古かったり不完全であったりする可能性があります。最新の情報は英語版をご利用ください。 | 2 | > ここに掲載されている情報は、古かったり不完全であったりする可能性があります。最新の情報は英語版をご利用ください。 |
| 3 | 3 | ||
| 4 | ![][cover] | ||
| 5 | |||
| 6 | <div align="center"> | ||
| 7 | |||
| 4 | [English](readme.md) | [中文](readme-zh_cn.md) | 日本語 | [Русский](readme-ru_ru.md) | 8 | [English](readme.md) | [中文](readme-zh_cn.md) | 日本語 | [Русский](readme-ru_ru.md) |
| 5 | 9 | ||
| 6 |  | 10 | [](https://github.com/SillyTavern/SillyTavern/stargazers) |
| 11 | [](https://github.com/SillyTavern/SillyTavern/network) | ||
| 12 | [](https://github.com/SillyTavern/SillyTavern/issues) | ||
| 13 | [](https://github.com/SillyTavern/SillyTavern/pulls) | ||
| 14 | |||
| 15 | </div> | ||
| 16 | |||
| 17 | --- | ||
| 7 | 18 | ||
| 8 | モバイルデバイスにも適したレイアウト・マルチAPI(KoboldAI/CPP、Horde、NovelAI、Ooba、OpenAI、OpenRouter、Claude、Scale)、VN ライクな Waifu モード、Stable Diffusion、TTS、WorldInfo(伝承本)、カスタマイズ可能なUI、自動翻訳、大量のプロンプトオプション+サードパーティの拡張機能をインストールする機能 | 19 | モバイルデバイスにも適したレイアウト・マルチAPI(KoboldAI/CPP、Horde、NovelAI、Ooba、OpenAI、OpenRouter、Claude、Scale)、VN ライクな Waifu モード、Stable Diffusion、TTS、WorldInfo(伝承本)、カスタマイズ可能なUI、自動翻訳、大量のプロンプトオプション+サードパーティの拡張機能をインストールする機能 |
| 9 | 20 | ||
| @@ -284,8 +295,8 @@ ST サーバを再起動すると、ユーザ名とパスワードさえ知っ | |||
| 284 | 295 | ||
| 285 | ## スクリーンショット | 296 | ## スクリーンショット |
| 286 | 297 | ||
| 287 | <img width="400" alt="image" src="https://user-images.githubusercontent.com/18619528/228649245-8061c60f-63dc-488e-9325-f151b7a3ec2d.png"> | 298 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> |
| 288 | <img width="400" alt="image" src="https://user-images.githubusercontent.com/18619528/228649856-fbdeef05-d727-4d5a-be80-266cbbc6b811.png"> | 299 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> |
| 289 | 300 | ||
| 290 | ## ライセンスとクレジット | 301 | ## ライセンスとクレジット |
| 291 | 302 | ||
| @@ -314,3 +325,6 @@ ST サーバを再起動すると、ユーザ名とパスワードさえ知っ | |||
| 314 | * @doloroushyeonse による韓国語翻訳 | 325 | * @doloroushyeonse による韓国語翻訳 |
| 315 | * k_euler_a による Horde のサポート <https://github.com/Teashrock> | 326 | * k_euler_a による Horde のサポート <https://github.com/Teashrock> |
| 316 | * [@XXpE3](https://github.com/XXpE3) による中国語翻訳、中国語 ISSUES の連絡先は @XXpE3 | 327 | * [@XXpE3](https://github.com/XXpE3) による中国語翻訳、中国語 ISSUES の連絡先は @XXpE3 |
| 328 | |||
| 329 | <!-- LINK GROUP --> | ||
| 330 | [cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 | ||
| @@ -3,9 +3,20 @@ | |||
| 3 | 3 | ||
| 4 | <a name="readme-top"></a> | 4 | <a name="readme-top"></a> |
| 5 | 5 | ||
| 6 | ![][cover] | ||
| 7 | |||
| 8 | <div align="center"> | ||
| 9 | |||
| 6 | [English](readme.md) | [中文](readme-zh_cn.md) | [日本語](readme-ja_jp.md) | Русский | 10 | [English](readme.md) | [中文](readme-zh_cn.md) | [日本語](readme-ja_jp.md) | Русский |
| 7 | 11 | ||
| 8 | ![][cover] | 12 | [](https://github.com/SillyTavern/SillyTavern/stargazers) |
| 13 | [](https://github.com/SillyTavern/SillyTavern/network) | ||
| 14 | [](https://github.com/SillyTavern/SillyTavern/issues) | ||
| 15 | [](https://github.com/SillyTavern/SillyTavern/pulls) | ||
| 16 | |||
| 17 | </div> | ||
| 18 | |||
| 19 | --- | ||
| 9 | 20 | ||
| 10 | Мобайл-френдли интерфейс, поддержка множества API (KoboldAI/CPP, Horde, NovelAI, Ooba, OpenAI, OpenRouter, Claude, Scale), ВН-образный режим Вайфу, Stable Diffusion, TTS, поддержка миров (лорбуков), кастомизируемый UI, автоперевод, тончайшая настройка промптов + возможность устанавливать расширения. | 21 | Мобайл-френдли интерфейс, поддержка множества API (KoboldAI/CPP, Horde, NovelAI, Ooba, OpenAI, OpenRouter, Claude, Scale), ВН-образный режим Вайфу, Stable Diffusion, TTS, поддержка миров (лорбуков), кастомизируемый UI, автоперевод, тончайшая настройка промптов + возможность устанавливать расширения. |
| 11 | 22 | ||
| @@ -29,8 +40,8 @@ SillyTavern — это форк версии TavernAI 1.2.8, который ра | |||
| 29 | 40 | ||
| 30 | ## Скриншоты | 41 | ## Скриншоты |
| 31 | 42 | ||
| 32 | <img width="400" alt="image" src="https://github.com/SillyTavern/SillyTavern/assets/61471128/e902c7a2-45a6-4415-97aa-c59c597669c1"> | 43 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> |
| 33 | <img width="400" alt="image" src="https://github.com/SillyTavern/SillyTavern/assets/61471128/f8a79c47-4fe9-4564-9e4a-bf247ed1c961"> | 44 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> |
| 34 | 45 | ||
| 35 | ### Ветки | 46 | ### Ветки |
| 36 | 47 | ||
| @@ -355,7 +366,7 @@ SillyTavern сохраняет ключи от ваших API в файле `sec | |||
| 355 | 366 | ||
| 356 | <!-- LINK GROUP --> | 367 | <!-- LINK GROUP --> |
| 357 | [back-to-top]: https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square | 368 | [back-to-top]: https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square |
| 358 | [cover]: https://github.com/SillyTavern/SillyTavern/assets/18619528/c2be4c3f-aada-4f64-87a3-ae35a68b61a4 | 369 | [cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 |
| 359 | [discord-link]: https://discord.gg/sillytavern | 370 | [discord-link]: https://discord.gg/sillytavern |
| 360 | [discord-shield]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square | 371 | [discord-shield]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square |
| 361 | [discord-shield-badge]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge | 372 | [discord-shield-badge]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge |
| @@ -1,9 +1,20 @@ | |||
| 1 | > [!IMPORTANT] | 1 | > [!IMPORTANT] |
| 2 | > 这里的信息可能已经过时或不完整,仅供您参考。请使用英文版本获取最新信息。 | 2 | > 这里的信息可能已经过时或不完整,仅供您参考。请使用英文版本获取最新信息。 |
| 3 | 3 | ||
| 4 | ![][cover] | ||
| 5 | |||
| 6 | <div align="center"> | ||
| 7 | |||
| 4 | [English](readme.md) | 中文 | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) | 8 | [English](readme.md) | 中文 | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) |
| 5 | 9 | ||
| 6 |  | 10 | [](https://github.com/SillyTavern/SillyTavern/stargazers) |
| 11 | [](https://github.com/SillyTavern/SillyTavern/network) | ||
| 12 | [](https://github.com/SillyTavern/SillyTavern/issues) | ||
| 13 | [](https://github.com/SillyTavern/SillyTavern/pulls) | ||
| 14 | |||
| 15 | </div> | ||
| 16 | |||
| 17 | --- | ||
| 7 | 18 | ||
| 8 | 移动设备界面友好,多种人工智能服务或模型支持(KoboldAI/CPP, Horde, NovelAI, Ooba, OpenAI, OpenRouter, Claude, Scale),类似 Galgame 的 老 婆 模 式,Horde SD,文本系统语音生成,世界信息(Lorebooks),可定制的界面,自动翻译,和比你所需要的更多的 Prompt。附带扩展服务,支持文本绘画生成与语音生成和基于向量数据库 的聊天信息总结。 | 19 | 移动设备界面友好,多种人工智能服务或模型支持(KoboldAI/CPP, Horde, NovelAI, Ooba, OpenAI, OpenRouter, Claude, Scale),类似 Galgame 的 老 婆 模 式,Horde SD,文本系统语音生成,世界信息(Lorebooks),可定制的界面,自动翻译,和比你所需要的更多的 Prompt。附带扩展服务,支持文本绘画生成与语音生成和基于向量数据库 的聊天信息总结。 |
| 9 | 20 | ||
| @@ -278,8 +289,8 @@ SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。 | |||
| 278 | 289 | ||
| 279 | ## 屏幕截图 | 290 | ## 屏幕截图 |
| 280 | 291 | ||
| 281 | <img width="400" alt="image" src="https://user-images.githubusercontent.com/18619528/228649245-8061c60f-63dc-488e-9325-f151b7a3ec2d.png"> | 292 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> |
| 282 | <img width="400" alt="image" src="https://user-images.githubusercontent.com/18619528/228649856-fbdeef05-d727-4d5a-be80-266cbbc6b811.png"> | 293 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> |
| 283 | 294 | ||
| 284 | ## 许可证和贡献 | 295 | ## 许可证和贡献 |
| 285 | 296 | ||
| @@ -306,3 +317,6 @@ SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。 | |||
| 306 | * Default content (characters and lore books) provided by @OtisAlejandro, @RossAscends and @kallmeflocc | 317 | * Default content (characters and lore books) provided by @OtisAlejandro, @RossAscends and @kallmeflocc |
| 307 | * Korean translation by @doloroushyeonse | 318 | * Korean translation by @doloroushyeonse |
| 308 | * 中文翻译由 [@XXpE3](https://github.com/XXpE3) 完成,中文 ISSUES 可以联系 @XXpE3 | 319 | * 中文翻译由 [@XXpE3](https://github.com/XXpE3) 完成,中文 ISSUES 可以联系 @XXpE3 |
| 320 | |||
| 321 | <!-- LINK GROUP --> | ||
| 322 | [cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 | ||
| @@ -1,76 +1,103 @@ | |||
| 1 | <a name="readme-top"></a> | 1 | <a name="readme-top"></a> |
| 2 | 2 | ||
| 3 | English | [中文](readme-zh_cn.md) | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) | ||
| 4 | |||
| 5 | ![][cover] | 3 | ![][cover] |
| 6 | 4 | ||
| 7 | Mobile-friendly layout, Multi-API (KoboldAI/CPP, Horde, NovelAI, Ooba, OpenAI, OpenRouter, Claude, Scale), VN-like Waifu Mode, Stable Diffusion, TTS, WorldInfo (lorebooks), customizable UI, auto-translate, and more prompt options than you'd ever want or need + ability to install third-party extensions. | 5 | <div align="center"> |
| 8 | 6 | ||
| 9 | Based on a fork of [TavernAI](https://github.com/TavernAI/TavernAI) 1.2.8 | 7 | English | [中文](readme-zh_cn.md) | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) |
| 10 | 8 | ||
| 11 | ## Important news! | 9 | [](https://github.com/SillyTavern/SillyTavern/stargazers) |
| 10 | [](https://github.com/SillyTavern/SillyTavern/network) | ||
| 11 | [](https://github.com/SillyTavern/SillyTavern/issues) | ||
| 12 | [](https://github.com/SillyTavern/SillyTavern/pulls) | ||
| 12 | 13 | ||
| 13 | 1. We have created a [Documentation website](https://docs.sillytavern.app/) to answer most of your questions and help you get started. | 14 | </div> |
| 14 | 15 | ||
| 15 | 2. Missing extensions after the update? Since the 1.10.6 release version, most of the previously built-in extensions have been converted to downloadable add-ons. You can download them via the built-in "Download Extensions and Assets" menu in the extensions panel (stacked blocks icon in the top bar). | 16 | --- |
| 16 | 17 | ||
| 17 | 3. Unsupported platform: android arm LEtime-web. 32-bit Android requires an external dependency that can't be installed with npm. Use the following command to install it: `pkg install esbuild`. Then run the usual installation steps. | 18 | SillyTavern provides a single unified interface for many LLM APIs (KoboldAI/CPP, Horde, NovelAI, Ooba, Tabby, OpenAI, OpenRouter, Claude, Mistral and more), a mobile-friendly layout, Visual Novel Mode, Automatic1111 & ComfyUI API image generation integration, TTS, WorldInfo (lorebooks), customizable UI, auto-translate, more prompt options than you'd ever want or need, and endless growth potential via third-party extensions. |
| 18 | 19 | ||
| 19 | ### Brought to you by Cohee, RossAscends, and the SillyTavern community | 20 | We have a [Documentation website](https://docs.sillytavern.app/) to answer most of your questions and help you get started. |
| 20 | 21 | ||
| 21 | ### What is SillyTavern or TavernAI? | 22 | ## What is SillyTavern? |
| 22 | 23 | ||
| 23 | SillyTavern is a user interface you can install on your computer (and Android phones) that allows you to interact with text generation AIs and chat/roleplay with characters you or the community create. | 24 | SillyTavern (or ST for short) is a locally installed user interface that allows you to interact with text generation LLMs, image generation engines, and TTS voice models. |
| 24 | 25 | ||
| 25 | SillyTavern is a fork of TavernAI 1.2.8 which is under more active development and has added many major features. At this point, they can be thought of as completely independent programs. | 26 | Beginning in February 2023 as a fork of TavernAI 1.2.8, SillyTavern now has over 100 contributors and 2 years of independent development under its belt, and continues to serve as a leading software for savvy AI hobbyists. |
| 26 | 27 | ||
| 27 | ## Screenshots | 28 | ## Our Vision |
| 28 | 29 | ||
| 29 | <img width="400" alt="image" src="https://github.com/SillyTavern/SillyTavern/assets/61471128/e902c7a2-45a6-4415-97aa-c59c597669c1"> | 30 | 1. We aim to empower users with as much utility and control over their LLM prompts as possible. The steep learning curve is part of the fun! |
| 30 | <img width="400" alt="image" src="https://github.com/SillyTavern/SillyTavern/assets/61471128/f8a79c47-4fe9-4564-9e4a-bf247ed1c961"> | 31 | 2. We do not provide any online or hosted services, nor programmatically track any user data. |
| 32 | 3. SillyTavern is a passion project brought to you by a dedicated community of LLM enthusiasts, and will always be free and open sourced. | ||
| 31 | 33 | ||
| 32 | ### Branches | 34 | ## Branches |
| 33 | 35 | ||
| 34 | SillyTavern is being developed using a two-branch system to ensure a smooth experience for all users. | 36 | SillyTavern is being developed using a two-branch system to ensure a smooth experience for all users. |
| 35 | 37 | ||
| 36 | * release -🌟 **Recommended for most users.** This is the most stable and recommended branch, updated only when major releases are pushed. It's suitable for the majority of users. | 38 | * `release` -🌟 **Recommended for most users.** This is the most stable and recommended branch, updated only when major releases are pushed. It's suitable for the majority of users. Typically updated once a month. |
| 37 | * staging - ⚠️ **Not recommended for casual use.** This branch has the latest features, but be cautious as it may break at any time. Only for power users and enthusiasts. | 39 | * `staging` - ⚠️ **Not recommended for casual use.** This branch has the latest features, but be cautious as it may break at any time. Only for power users and enthusiasts. Updates several times daily. |
| 38 | 40 | ||
| 39 | If you're not familiar with using the git CLI or don't understand what a branch is, don't worry! The release branch is always the preferable option for you. | 41 | If you're not familiar with using the git CLI or don't understand what a branch is, don't worry! The release branch is always the preferable option for you. |
| 40 | 42 | ||
| 41 | ### What do I need other than SillyTavern? | 43 | ## What do I need other than SillyTavern? |
| 42 | 44 | ||
| 43 | On its own SillyTavern is useless, as it's just a user interface. You have to have access to an AI system backend that can act as the roleplay character. There are various supported backends: OpenAPI API (GPT), KoboldAI (either running locally or on Google Colab), and more. You can read more about this in [the FAQ](https://docs.sillytavern.app/usage/faq/). | 45 | Since SillyTavern is only an interface, you will need access to an LLM backend to provide inference. You can use AI Horde for instant out-of-the-box chatting. Aside from that, we support many other local and cloud-based LLM backends: OpenAI-compatible API, KoboldAI, Tabby, and many more. You can read more about our supported APIs in [the FAQ](https://docs.sillytavern.app/usage/api-connections/). |
| 44 | 46 | ||
| 45 | ### Do I need a powerful PC to run SillyTavern? | 47 | ### Do I need a powerful PC to run SillyTavern? |
| 46 | 48 | ||
| 47 | Since SillyTavern is only a user interface, it has tiny hardware requirements, it will run on anything. It's the AI system backend that needs to be powerful. | 49 | The hardware requirements are minimal: it will run on anything that can run NodeJS 18 or higher. If you intend to do LLM inference on your local machine, we recommend a 3000-series NVIDIA graphics card with at least 6GB of VRAM. Check your backend's documentation for more details. |
| 50 | |||
| 51 | ### Suggested Backends (not affiliated) | ||
| 52 | |||
| 53 | * [AI Horde](https://aihorde.net/) - use models hosted by volunteers. Requires no further setup | ||
| 54 | * [KoboldCpp](https://github.com/LostRuins/koboldcpp) - a community's favorite for running GGUF models locally | ||
| 55 | * [tabbyAPI](https://github.com/theroyallab/tabbyAPI) - a popular, lightweight, locally-hosted exl2 inference API | ||
| 56 | * [OpenRouter](https://openrouter.ai) - a single API for many cloud providers (OpenAI, Claude, Meta Llama, etc.) as well as popular community models. | ||
| 48 | 57 | ||
| 49 | ## Questions or suggestions? | 58 | ## Questions or suggestions? |
| 50 | 59 | ||
| 51 | ### We now have a community Discord server | 60 | ### Discord server |
| 52 | 61 | ||
| 53 | | [![][discord-shield-badge]][discord-link] | [Join our Discord community!](https://discord.gg/sillytavern) Get support, share favorite characters and prompts. | | 62 | | [![][discord-shield-badge]][discord-link] | [Join our Discord community!](https://discord.gg/sillytavern) Get support, share favorite characters and prompts. | |
| 54 | | :---------------------------------------- | :----------------------------------------------------------------------------------------------------------------- | | 63 | | :---------------------------------------- | :----------------------------------------------------------------------------------------------------------------- | |
| 55 | 64 | ||
| 56 | Or get in touch with the developers directly: | 65 | Or get in touch with the developers directly: |
| 57 | 66 | ||
| 58 | * Discord: cohee or rossascends | 67 | * Discord: cohee, rossascends, wolfsblvt |
| 59 | * Reddit: [/u/RossAscends](https://www.reddit.com/user/RossAscends/) or [/u/sillylossy](https://www.reddit.com/user/sillylossy/) | 68 | * Reddit: [/u/RossAscends](https://www.reddit.com/user/RossAscends/), [/u/sillylossy](https://www.reddit.com/user/sillylossy/), [u/Wolfsblvt](https://www.reddit.com/user/Wolfsblvt/) |
| 60 | * [Post a GitHub issue](https://github.com/SillyTavern/SillyTavern/issues) | 69 | * [Post a GitHub issue](https://github.com/SillyTavern/SillyTavern/issues) |
| 61 | 70 | ||
| 62 | ## This version includes | 71 | ### I like your project! How do I contribute? |
| 72 | |||
| 73 | 1. Send pull requests. Learn how to contribute: [CONTRIBUTING.md](../CONTRIBUTING.md) | ||
| 74 | 2. Send feature suggestions and issue reports using the provided templates. | ||
| 75 | 3. Read this entire readme file and check the documentation website first, to avoid sending duplicate issues. | ||
| 76 | |||
| 77 | ## Screenshots | ||
| 78 | |||
| 79 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> | ||
| 80 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> | ||
| 81 | |||
| 82 | ## Character Cards | ||
| 83 | |||
| 84 | SillyTavern is built around the concept of "character cards". A character card is a collection of prompts that set the behavior of the LLM and is required to have persistent conversations in SillyTavern. They function similarly to ChatGPT's GPTs or Poe's bots. The content of a character card can be anything: an abstract scenario, an assistant tailored for a specific task, a famous personality or a fictional character. | ||
| 85 | |||
| 86 | The name field is the only required character card input. To start a neutral conversation with the language model, create a new card simply called "Assistant" and leave the rest of the boxes blank. For a more themed chat, you can provide the language model with various background details, behavior and writing patterns, and a scenario to jump start the chat. | ||
| 63 | 87 | ||
| 64 | * A heavily modified TavernAI 1.2.8 (more than 50% of code rewritten or optimized) | 88 | To have a quick conversation without selecting a character card or to just test the LLM connection, simply type your prompt input into the input bar on the Welcome Screen after opening SillyTavern. Please note that such chats are temporary and will not be saved. |
| 65 | * Swipes | 89 | |
| 66 | * Group chats: multi-bot rooms for characters to talk to you or each other | 90 | To get a general idea on how to define character cards, see the default character (Seraphina) or download selected community-made cards from the "Download Extensions & Assets" menu. |
| 67 | * Chat checkpoints / branching | 91 | |
| 68 | * Advanced KoboldAI / TextGen generation settings with a lot of community-made presets | 92 | ## Key Features |
| 93 | |||
| 94 | * Advanced text generation settings with many community-made presets | ||
| 69 | * World Info support: create rich lore or save tokens on your character card | 95 | * World Info support: create rich lore or save tokens on your character card |
| 70 | * [OpenRouter](https://openrouter.ai) connection for various APIs (Claude, GPT-4/3.5 and more) | 96 | * Group chats: multi-bot rooms for characters to talk to you and/or each other |
| 71 | * [Oobabooga's TextGen WebUI](https://github.com/oobabooga/text-generation-webui) API connection | 97 | * Rich UI customization options: theme colors, background images, custom CSS, and more |
| 72 | * [AI Horde](https://aihorde.net/) connection | 98 | * User personas: let the AI know a bit about you for greater immersion |
| 73 | * Prompt generation formatting tweaking | 99 | * Built-in RAG support: add documents to your chats for the AI to reference |
| 100 | * Extensive chat commands subsystem and own [scripting engine](https://docs.sillytavern.app/usage/st-script/) | ||
| 74 | 101 | ||
| 75 | ## Extensions | 102 | ## Extensions |
| 76 | 103 | ||
| @@ -78,83 +105,43 @@ SillyTavern has extensibility support. | |||
| 78 | 105 | ||
| 79 | * Character emotional expressions (sprites) | 106 | * Character emotional expressions (sprites) |
| 80 | * Auto-Summary of the chat history | 107 | * Auto-Summary of the chat history |
| 81 | * Sending images to chat, and the AI interpreting the content | 108 | * Automatic UI and chat translation |
| 82 | * Stable Diffusion image generation (5 chat-related presets plus 'free mode') | 109 | * Stable Diffusion/FLUX/DALL-E image generation |
| 83 | * Text-to-speech for AI response messages (via ElevenLabs, Silero, or the OS's System TTS) | 110 | * Text-to-speech for AI response messages (via ElevenLabs, Silero, or the OS's System TTS) |
| 84 | * Many more available to download from the "Download Extensions & Assets" menu. | 111 | * Web Search capabilities for adding additional real world context to your prompts |
| 112 | * Many more are available to download from the "Download Extensions & Assets" menu. | ||
| 85 | 113 | ||
| 86 | Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern.app/). | 114 | Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern.app/). |
| 87 | 115 | ||
| 88 | ## UI/CSS/Quality of Life tweaks by RossAscends | ||
| 89 | |||
| 90 | * Mobile UI optimized for iOS, and supports saving a shortcut to the home screen and opening in fullscreen mode. | ||
| 91 | * HotKeys | ||
| 92 | * Up = Edit last message in chat | ||
| 93 | * Ctrl+Up = Edit last USER message in chat | ||
| 94 | * Left = swipe left | ||
| 95 | * Right = swipe right (NOTE: swipe hotkeys are disabled when the chat bar has something typed into it) | ||
| 96 | * Ctrl+Left = view locally stored variables (in the browser console window) | ||
| 97 | * Enter (with chat bar selected) = send your message to AI | ||
| 98 | * Ctrl+Enter = Regenerate the last AI response | ||
| 99 | |||
| 100 | * User Name Changes and Character Deletion no longer force the page to refresh. | ||
| 101 | |||
| 102 | * Toggle option to automatically connect to API on page load. | ||
| 103 | * Toggle option to automatically load the most recently viewed character on page load. | ||
| 104 | * Better Token Counter - works on unsaved characters, and shows both permanent and temporary tokens. | ||
| 105 | |||
| 106 | * Better Past Chats View | ||
| 107 | * New Chat filenames are saved in a readable format of "(character) - (when it was created)" | ||
| 108 | * Chat preview increased from 40 characters to 300. | ||
| 109 | * Multiple options for characters list sorting (by name, creation date, chat sizes). | ||
| 110 | |||
| 111 | * By default the left and right settings panel will close when you click away from it. | ||
| 112 | * Clicking the Lock on the nav panel will hold the panel open, and this setting be remembered across sessions. | ||
| 113 | * Nav panel status of open or closed will also be saved across sessions. | ||
| 114 | |||
| 115 | * Customizable chat UI: | ||
| 116 | * Play a sound when a new message arrives | ||
| 117 | * Switch between round or rectangle avatar styles | ||
| 118 | * Have a wider chat window on the desktop | ||
| 119 | * Optional semi-transparent glass-like panels | ||
| 120 | * Customizable page colors for 'main text', 'quoted text', and 'italics text'. | ||
| 121 | * Customizable UI background color and blur amount | ||
| 122 | |||
| 123 | # ⌛ Installation | 116 | # ⌛ Installation |
| 124 | 117 | ||
| 125 | > \[!WARNING] | 118 | > \[!WARNING] |
| 119 | > | ||
| 126 | > * DO NOT INSTALL INTO ANY WINDOWS CONTROLLED FOLDER (Program Files, System32, etc). | 120 | > * DO NOT INSTALL INTO ANY WINDOWS CONTROLLED FOLDER (Program Files, System32, etc). |
| 127 | > * DO NOT RUN START.BAT WITH ADMIN PERMISSIONS | 121 | > * DO NOT RUN START.BAT WITH ADMIN PERMISSIONS |
| 128 | > * INSTALLATION ON WINDOWS 7 IS IMPOSSIBLE AS IT CAN NOT RUN NODEJS 18.16 | 122 | > * INSTALLATION ON WINDOWS 7 IS IMPOSSIBLE AS IT CAN NOT RUN NODEJS 18.16 |
| 129 | 123 | ||
| 130 | ## 🪟 Windows | 124 | ## 🪟 Windows |
| 131 | 125 | ||
| 132 | ## Installing via Git | 126 | ### Installing via Git |
| 133 | 1. Install [NodeJS](https://nodejs.org/en) (latest LTS version is recommended) | ||
| 134 | 2. Install [Git for Windows](https://gitforwindows.org/) | ||
| 135 | 3. Open Windows Explorer (`Win+E`) | ||
| 136 | 4. Browse to or Create a folder that is not controlled or monitored by Windows. (ex: C:\MySpecialFolder\) | ||
| 137 | 5. Open a Command Prompt inside that folder by clicking in the 'Address Bar' at the top, typing `cmd`, and pressing Enter. | ||
| 138 | 6. Once the black box (Command Prompt) pops up, type ONE of the following into it and press Enter: | ||
| 139 | 127 | ||
| 140 | - for Release Branch: `git clone https://github.com/SillyTavern/SillyTavern -b release` | 128 | 1. Install [NodeJS](https://nodejs.org/en) (latest LTS version is recommended) |
| 141 | - for Staging Branch: `git clone https://github.com/SillyTavern/SillyTavern -b staging` | 129 | 2. Install [Git for Windows](https://gitforwindows.org/) |
| 130 | 3. Open Windows Explorer (`Win+E`) | ||
| 131 | 4. Browse to or Create a folder that is not controlled or monitored by Windows. (ex: C:\MySpecialFolder\) | ||
| 132 | 5. Open a Command Prompt inside that folder by clicking in the 'Address Bar' at the top, typing `cmd`, and pressing Enter. | ||
| 133 | 6. Once the black box (Command Prompt) pops up, type ONE of the following into it and press Enter: | ||
| 142 | 134 | ||
| 143 | 7. Once everything is cloned, double-click `Start.bat` to make NodeJS install its requirements. | 135 | * for Release Branch: `git clone https://github.com/SillyTavern/SillyTavern -b release` |
| 144 | 8. The server will then start, and SillyTavern will pop up in your browser. | 136 | * for Staging Branch: `git clone https://github.com/SillyTavern/SillyTavern -b staging` |
| 145 | 137 | ||
| 146 | ## Installing via SillyTavern Launcher | 138 | 7. Once everything is cloned, double-click `Start.bat` to make NodeJS install its requirements. |
| 147 | 1. On your keyboard: press **`WINDOWS + R`** to open Run dialog box. Then, run the following command to install git: | 139 | 8. The server will then start, and SillyTavern will pop up in your browser. |
| 148 | ```shell | 140 | |
| 149 | cmd /c winget install -e --id Git.Git | 141 | ### Installing via GitHub Desktop |
| 150 | ``` | ||
| 151 | 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: | ||
| 152 | ```shell | ||
| 153 | git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher && start installer.bat | ||
| 154 | ``` | ||
| 155 | 142 | ||
| 156 | ## Installing via GitHub Desktop | ||
| 157 | (This allows git usage **only** in GitHub Desktop, if you want to use `git` on the command line too, you also need to install [Git for Windows](https://gitforwindows.org/)) | 143 | (This allows git usage **only** in GitHub Desktop, if you want to use `git` on the command line too, you also need to install [Git for Windows](https://gitforwindows.org/)) |
| 144 | |||
| 158 | 1. Install [NodeJS](https://nodejs.org/en) (latest LTS version is recommended) | 145 | 1. Install [NodeJS](https://nodejs.org/en) (latest LTS version is recommended) |
| 159 | 2. Install [GitHub Desktop](https://central.github.com/deployments/desktop/desktop/latest/win32) | 146 | 2. Install [GitHub Desktop](https://central.github.com/deployments/desktop/desktop/latest/win32) |
| 160 | 3. After installing GitHub Desktop, click on `Clone a repository from the internet....` (Note: You **do NOT need** to create a GitHub account for this step) | 147 | 3. After installing GitHub Desktop, click on `Clone a repository from the internet....` (Note: You **do NOT need** to create a GitHub account for this step) |
| @@ -172,50 +159,82 @@ For MacOS / Linux all of these will be done in a Terminal. | |||
| 172 | 1. Install git and nodeJS (the method for doing this will vary depending on your OS) | 159 | 1. Install git and nodeJS (the method for doing this will vary depending on your OS) |
| 173 | 2. Clone the repo | 160 | 2. Clone the repo |
| 174 | 161 | ||
| 175 | - for Release Branch: `git clone https://github.com/SillyTavern/SillyTavern -b release` | 162 | * for Release Branch: `git clone https://github.com/SillyTavern/SillyTavern -b release` |
| 176 | - for Staging Branch: `git clone https://github.com/SillyTavern/SillyTavern -b staging` | 163 | * for Staging Branch: `git clone https://github.com/SillyTavern/SillyTavern -b staging` |
| 177 | 164 | ||
| 178 | 3. `cd SillyTavern` to navigate into the install folder. | 165 | 3. `cd SillyTavern` to navigate into the install folder. |
| 179 | 4. Run the `start.sh` script with one of these commands: | 166 | 4. Run the `start.sh` script with one of these commands: |
| 180 | 167 | ||
| 181 | - `./start.sh` | 168 | * `./start.sh` |
| 182 | - `bash start.sh` | 169 | * `bash start.sh` |
| 170 | |||
| 171 | ## ⚡ Installing via SillyTavern Launcher | ||
| 172 | |||
| 173 | SillyTavern Launcher is an installation wizard that will help you get setup with many options, including installing a backend for local inference. | ||
| 174 | |||
| 175 | ### For Windows users | ||
| 183 | 176 | ||
| 184 | ## Installing via SillyTavern Launcher | 177 | 1. On your keyboard: press **`WINDOWS + R`** to open Run dialog box. Then, run the following command to install git: |
| 178 | |||
| 179 | ```shell | ||
| 180 | cmd /c winget install -e --id Git.Git | ||
| 181 | ``` | ||
| 182 | |||
| 183 | 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: | ||
| 184 | |||
| 185 | ```shell | ||
| 186 | git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher && start installer.bat | ||
| 187 | ``` | ||
| 185 | 188 | ||
| 186 | ### For Linux users | 189 | ### For Linux users |
| 190 | |||
| 187 | 1. Open your favorite terminal and install git | 191 | 1. Open your favorite terminal and install git |
| 188 | 2. Git clone the Sillytavern-Launcher with: | 192 | 2. Git clone the Sillytavern-Launcher with: |
| 193 | |||
| 189 | ```shell | 194 | ```shell |
| 190 | git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher | 195 | git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher |
| 191 | ``` | 196 | ``` |
| 192 | 3. Start the installer.sh with: | 197 | |
| 198 | 3. Start the installer.sh with: | ||
| 199 | |||
| 193 | ```shell | 200 | ```shell |
| 194 | chmod +x install.sh && ./install.sh | 201 | chmod +x install.sh && ./install.sh |
| 195 | ``` | 202 | ``` |
| 196 | 4. After installation start the launcher.sh with: | 203 | |
| 204 | 4. After installation start the launcher.sh with: | ||
| 205 | |||
| 197 | ```shell | 206 | ```shell |
| 198 | chmod +x launcher.sh && ./launcher.sh | 207 | chmod +x launcher.sh && ./launcher.sh |
| 199 | ``` | 208 | ``` |
| 200 | 209 | ||
| 201 | ### For Mac users | 210 | ### For Mac users |
| 202 | 1. Open a terminal and install brew with: | 211 | |
| 212 | 1. Open a terminal and install brew with: | ||
| 213 | |||
| 203 | ```shell | 214 | ```shell |
| 204 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | 215 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" |
| 205 | ``` | 216 | ``` |
| 206 | 2. Install git with: | 217 | |
| 218 | 2. Install git with: | ||
| 219 | |||
| 207 | ```shell | 220 | ```shell |
| 208 | brew install git | 221 | brew install git |
| 209 | ``` | 222 | ``` |
| 210 | 3. Git clone the Sillytavern-Launcher with: | 223 | |
| 224 | 3. Git clone the Sillytavern-Launcher with: | ||
| 225 | |||
| 211 | ```shell | 226 | ```shell |
| 212 | git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher | 227 | git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher |
| 213 | ``` | 228 | ``` |
| 214 | 4. Start the installer.sh with: | 229 | |
| 230 | 4. Start the installer.sh with: | ||
| 231 | |||
| 215 | ```shell | 232 | ```shell |
| 216 | chmod +x install.sh && ./install.sh | 233 | chmod +x install.sh && ./install.sh |
| 217 | ``` | 234 | ``` |
| 218 | 5. After installation start the launcher.sh with: | 235 | |
| 236 | 5. After installation start the launcher.sh with: | ||
| 237 | |||
| 219 | ```shell | 238 | ```shell |
| 220 | chmod +x launcher.sh && ./launcher.sh | 239 | chmod +x launcher.sh && ./launcher.sh |
| 221 | ``` | 240 | ``` |
| @@ -236,18 +255,18 @@ You will need two mandatory directory mappings and a port mapping to allow Silly | |||
| 236 | 255 | ||
| 237 | ##### Volume Mappings | 256 | ##### Volume Mappings |
| 238 | 257 | ||
| 239 | - [config] - The directory where SillyTavern configuration files will be stored on your host machine | 258 | * [config] - The directory where SillyTavern configuration files will be stored on your host machine |
| 240 | - [data] - The directory where SillyTavern user data (including characters) will be stored on your host machine | 259 | * [data] - The directory where SillyTavern user data (including characters) will be stored on your host machine |
| 241 | - [plugins] - (optional) The directory where SillyTavern server plugins will be stored on your host machine | 260 | * [plugins] - (optional) The directory where SillyTavern server plugins will be stored on your host machine |
| 242 | 261 | ||
| 243 | ##### Port Mappings | 262 | ##### Port Mappings |
| 244 | 263 | ||
| 245 | - [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. | 264 | * [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. |
| 246 | 265 | ||
| 247 | ##### Additional Settings | 266 | ##### Additional Settings |
| 248 | 267 | ||
| 249 | - [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/). | 268 | * [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/). |
| 250 | - [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. | 269 | * [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. |
| 251 | 270 | ||
| 252 | #### Install command | 271 | #### Install command |
| 253 | 272 | ||
| @@ -258,23 +277,28 @@ You will need two mandatory directory mappings and a port mapping to allow Silly | |||
| 258 | 277 | ||
| 259 | > Note that 8000 is a default listening port. Don't forget to use an appropriate port if you change it in the config. | 278 | > Note that 8000 is a default listening port. Don't forget to use an appropriate port if you change it in the config. |
| 260 | 279 | ||
| 261 | ## 📱 Mobile - Installing via termux | 280 | ## 📱 Installing via Termux on Android OS |
| 262 | 281 | ||
| 263 | > \[!NOTE] | 282 | > \[!NOTE] |
| 264 | > **SillyTavern can be run natively on Android phones using Termux. Please refer to this guide by ArroganceComplex#2659:** | 283 | > **SillyTavern can be run natively on Android devices using Termux, but we do not provide official support for this use case.** |
| 284 | > | ||
| 285 | > **Please refer to this guide by ArroganceComplex#2659:** | ||
| 286 | > | ||
| 265 | > * <https://rentry.org/STAI-Termux> | 287 | > * <https://rentry.org/STAI-Termux> |
| 266 | 288 | ||
| 289 | **Unsupported platform: android arm LEtime-web.** 32-bit Android requires an external dependency that can't be installed with npm. Use the following command to install it: `pkg install esbuild`. Then run the usual installation steps. | ||
| 267 | 290 | ||
| 268 | ## API keys management | 291 | ## API keys management |
| 269 | 292 | ||
| 270 | SillyTavern saves your API keys to a `secrets.json` file in the user data directory (`/data/default-user/secrets.json` is the default path). | 293 | SillyTavern saves your API keys to a `secrets.json` file in the user data directory (`/data/default-user/secrets.json` is the default path). |
| 271 | 294 | ||
| 272 | By default, they will not be exposed to a frontend after you enter them and reload the page. | 295 | By default, API keys will not be visible from the interface after you have saved them and refreshed the page. |
| 273 | 296 | ||
| 274 | In order to enable viewing your keys by clicking a button in the API block: | 297 | In order to enable viewing your keys: |
| 275 | 298 | ||
| 276 | 1. Set the value of `allowKeysExposure` to `true` in `config.yaml` file. | 299 | 1. Set the value of `allowKeysExposure` to `true` in `config.yaml` file. |
| 277 | 2. Restart the SillyTavern server. | 300 | 2. Restart the SillyTavern server. |
| 301 | 3. Click the 'View hidden API keys' link at the bottom right of the API Connection Panel. | ||
| 278 | 302 | ||
| 279 | ## Command-line arguments | 303 | ## Command-line arguments |
| 280 | 304 | ||
| @@ -292,134 +316,43 @@ Start.bat --port 8000 --listen false | |||
| 292 | 316 | ||
| 293 | ### Supported arguments | 317 | ### Supported arguments |
| 294 | 318 | ||
| 295 | | Option | Description | Type | Default | | 319 | | Option | Description | Type | |
| 296 | |-------------------------|------------------------------------------------------------------------------------------------------|----------|------------------------------| | 320 | |-------------------------|------------------------------------------------------------------------------------------------------|----------| |
| 297 | | `--version` | Show version number | boolean | | | 321 | | `--version` | Show version number | boolean | |
| 298 | | `--enableIPv6` | Enables IPv6. | boolean | false | | 322 | | `--enableIPv6` | Enables IPv6. | boolean | |
| 299 | | `--enableIPv4` | Enables IPv4. | boolean | true | | 323 | | `--enableIPv4` | Enables IPv4. | boolean | |
| 300 | | `--port` | Sets the port under which SillyTavern will run. If not provided falls back to yaml config 'port'. | number | 8000 | | 324 | | `--port` | Sets the port under which SillyTavern will run. If not provided falls back to yaml config 'port'. | number | |
| 301 | | `--dnsPreferIPv6` | Prefers IPv6 for dns. If not provided falls back to yaml config 'preferIPv6'. | boolean | false | | 325 | | `--dnsPreferIPv6` | Prefers IPv6 for dns. If not provided falls back to yaml config 'preferIPv6'. | boolean | |
| 302 | | `--autorun` | Automatically launch SillyTavern in the browser. If not provided falls back to yaml config 'autorun'.| boolean | false | | 326 | | `--autorun` | Automatically launch SillyTavern in the browser. If not provided falls back to yaml config 'autorun'.| boolean | |
| 303 | | `--autorunHostname` | The autorun hostname, probably best left on 'auto'. | string | null | | 327 | | `--autorunHostname` | The autorun hostname, probably best left on 'auto'. | string | |
| 304 | | `--autorunPortOverride` | Overrides the port for autorun. | string | null | | 328 | | `--autorunPortOverride` | Overrides the port for autorun. | string | |
| 305 | | `--listen` | SillyTavern is listening on all network interfaces. If not provided falls back to yaml config 'listen'.| boolean | false | | 329 | | `--listen` | SillyTavern is listening on all network interfaces. If not provided falls back to yaml config 'listen'.| boolean | |
| 306 | | `--corsProxy` | Enables CORS proxy. If not provided falls back to yaml config 'enableCorsProxy'. | boolean | false | | 330 | | `--corsProxy` | Enables CORS proxy. If not provided falls back to yaml config 'enableCorsProxy'. | boolean | |
| 307 | | `--disableCsrf` | Disables CSRF protection | boolean | null | | 331 | | `--disableCsrf` | Disables CSRF protection | boolean | |
| 308 | | `--ssl` | Enables SSL | boolean | false | | 332 | | `--ssl` | Enables SSL | boolean | |
| 309 | | `--certPath` | Path to your certificate file. | string | "certs/cert.pem" | | 333 | | `--certPath` | Path to your certificate file. | string | |
| 310 | | `--keyPath` | Path to your private key file. | string | "certs/privkey.pem" | | 334 | | `--keyPath` | Path to your private key file. | string | |
| 311 | | `--whitelist` | Enables whitelist mode | boolean | null | | 335 | | `--whitelist` | Enables whitelist mode | boolean | |
| 312 | | `--dataRoot` | Root directory for data storage | string | null | | 336 | | `--dataRoot` | Root directory for data storage | string | |
| 313 | | `--avoidLocalhost` | Avoids using 'localhost' for autorun in auto mode. | boolean | null | | 337 | | `--avoidLocalhost` | Avoids using 'localhost' for autorun in auto mode. | boolean | |
| 314 | | `--basicAuthMode` | Enables basic authentication | boolean | null | | 338 | | `--basicAuthMode` | Enables basic authentication | boolean | |
| 315 | | `--requestProxyEnabled` | Enables a use of proxy for outgoing requests | boolean | null | | 339 | | `--requestProxyEnabled` | Enables a use of proxy for outgoing requests | boolean | |
| 316 | | `--requestProxyUrl` | Request proxy URL (HTTP or SOCKS protocols) | string | null | | 340 | | `--requestProxyUrl` | Request proxy URL (HTTP or SOCKS protocols) | string | |
| 317 | | `--requestProxyBypass` | Request proxy bypass list (space separated list of hosts) | array | null | | 341 | | `--requestProxyBypass` | Request proxy bypass list (space separated list of hosts) | array | |
| 318 | 342 | ||
| 319 | ## Remote connections | 343 | ## Remote connections |
| 320 | 344 | ||
| 321 | Most often this is for people who want to use SillyTavern on their mobile phones while their PC runs the ST server on the same wifi network. | 345 | Most often this is for people who want to use SillyTavern on their mobile phones while their PC runs the ST server on the same Wi-Fi network. However, it can be used to allow remote connections from anywhere as well. |
| 322 | |||
| 323 | However, it can be used to allow remote connections from anywhere as well. | ||
| 324 | |||
| 325 | **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).** | ||
| 326 | |||
| 327 | ### 1. Managing whitelisted IPs | ||
| 328 | |||
| 329 | * Create a new text file inside your SillyTavern base install folder called `whitelist.txt`. | ||
| 330 | * Open the file in a text editor, and add a list of IPs you want to be allowed to connect. | ||
| 331 | |||
| 332 | *Both individual IPs and wildcard IP ranges are accepted. Examples:* | ||
| 333 | |||
| 334 | ```txt | ||
| 335 | 192.168.0.1 | ||
| 336 | 192.168.0.20 | ||
| 337 | ``` | ||
| 338 | |||
| 339 | or | ||
| 340 | |||
| 341 | ```txt | ||
| 342 | 192.168.0.* | ||
| 343 | ``` | ||
| 344 | |||
| 345 | (the above wildcard IP range will allow any device on the local network to connect) | ||
| 346 | |||
| 347 | CIDR masks are also accepted (eg. 10.0.0.0/24). | ||
| 348 | |||
| 349 | * Save the `whitelist.txt` file. | ||
| 350 | * Restart your ST server. | ||
| 351 | |||
| 352 | Now devices which have the IP specified in the file will be able to connect. | ||
| 353 | |||
| 354 | *Note: `config.yaml` also has a `whitelist` array, which you can use in the same way, but this array will be ignored if `whitelist.txt` exists.* | ||
| 355 | |||
| 356 | ### 2. Getting the IP for the ST host machine | ||
| 357 | |||
| 358 | After the whitelist has been setup, you'll need the IP of the ST-hosting device. | ||
| 359 | |||
| 360 | If the ST-hosting device is on the same wifi network, you will use the ST-host's internal wifi IP: | ||
| 361 | |||
| 362 | * For Windows: windows button > type `cmd.exe` in the search bar > type `ipconfig` in the console, hit Enter > look for `IPv4` listing. | ||
| 363 | |||
| 364 | If you (or someone else) want to connect to your hosted ST while not being on the same network, you will need the public IP of your ST-hosting device. | ||
| 365 | |||
| 366 | * While using the ST-hosting device, access [this page](https://whatismyipaddress.com/) and look for `IPv4`. This is what you would use to connect from the remote device. | ||
| 367 | 346 | ||
| 368 | ### 3. Connect the remote device to the ST host machine | 347 | Read the detailed guide on how to set up remote connections in the [Docs](https://docs.sillytavern.app/usage/remoteconnections/). |
| 369 | 348 | ||
| 370 | Whatever IP you ended up with for your situation, you will put that IP address and port number into the remote device's web browser. | 349 | You may also want to configure SillyTavern user profiles with (optional) password protection: [Users](https://docs.sillytavern.app/installation/st-1.12.0-migration-guide/#users). |
| 371 | |||
| 372 | A typical address for an ST host on the same wifi network would look like this: | ||
| 373 | |||
| 374 | `http://192.168.0.5:8000` | ||
| 375 | |||
| 376 | Use http:// NOT https:// | ||
| 377 | |||
| 378 | ### Opening your ST to all IPs | ||
| 379 | |||
| 380 | We do not recommend doing this, but you can open `config.yaml` and change `whitelistMode` to `false`. | ||
| 381 | |||
| 382 | You must remove (or rename) `whitelist.txt` in the SillyTavern base install folder if it exists. | ||
| 383 | |||
| 384 | This is usually an insecure practice, so we require you to set a username and password when you do this. | ||
| 385 | |||
| 386 | The username and password are set in `config.yaml`. | ||
| 387 | |||
| 388 | After restarting your ST server, any device will be able to connect to it, regardless of their IP as long as they know the username and password. | ||
| 389 | |||
| 390 | ### Still Unable To Connect? | ||
| 391 | |||
| 392 | * Create an inbound/outbound firewall rule for the port found in `config.yaml`. Do NOT mistake this for port-forwarding on your router, otherwise, someone could find your chat logs and that's a big no-no. | ||
| 393 | * Enable the Private Network profile type in Settings > Network and Internet > Ethernet. This is VERY important for Windows 11, otherwise, you would be unable to connect even with the aforementioned firewall rules. | ||
| 394 | 350 | ||
| 395 | ## Performance issues? | 351 | ## Performance issues? |
| 396 | 352 | ||
| 397 | Try enabling the No Blur Effect (Fast UI) mode on the User settings panel. | 353 | 1. Disable the Blur Effect and enable Reduced Motion on the User Settings panel (UI Theme toggles category). |
| 398 | 354 | 2. If using response streaming, set the streaming FPS to a lower value (10-15 FPS is recommended). | |
| 399 | ## I like your project! How do I contribute? | 355 | 3. Make sure the browser is enabled to use GPU acceleration for rendering. |
| 400 | |||
| 401 | ### DO's | ||
| 402 | |||
| 403 | 1. Send pull requests | ||
| 404 | 2. Send feature suggestions and issue reports using established templates | ||
| 405 | 3. Read the readme file and built-in documentation before asking anything | ||
| 406 | |||
| 407 | ### DONT's | ||
| 408 | |||
| 409 | 1. Offer monetary donations | ||
| 410 | 2. Send bug reports without providing any context | ||
| 411 | 3. Ask the questions that were already answered numerous times | ||
| 412 | |||
| 413 | ## Where can I find the old backgrounds? | ||
| 414 | |||
| 415 | We're moving to a 100% original content only policy, so old background images have been removed from this repository. | ||
| 416 | |||
| 417 | You can find them archived here: | ||
| 418 | |||
| 419 | <https://files.catbox.moe/1xevnc.zip> | ||
| 420 | |||
| 421 | |||
| 422 | |||
| 423 | 356 | ||
| 424 | ## License and credits | 357 | ## License and credits |
| 425 | 358 | ||
| @@ -428,32 +361,19 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 428 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 361 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 429 | GNU Affero General Public License for more details.** | 362 | GNU Affero General Public License for more details.** |
| 430 | 363 | ||
| 431 | * TAI Base by Humi: MIT | 364 | * [TavernAI](https://github.com/TavernAI/TavernAI) 1.2.8 by Humi: MIT License |
| 432 | * Cohee's modifications and derived code: AGPL v3 | 365 | * Portions of CncAnon's TavernAITurbo mod used with permission |
| 433 | * RossAscends' additions: AGPL v3 | 366 | * Visual Novel Mode inspired by the work of PepperTaco (<https://github.com/peppertaco/Tavern/>) |
| 434 | * Portions of CncAnon's TavernAITurbo mod: Unknown license | ||
| 435 | * kingbri's various commits and suggestions (<https://github.com/bdashore3>) | ||
| 436 | * city_unit's extensions and various QoL features (<https://github.com/city-unit>) | ||
| 437 | * StefanDanielSchwarz's various commits and bug reports (<https://github.com/StefanDanielSchwarz>) | ||
| 438 | * Waifu mode inspired by the work of PepperTaco (<https://github.com/peppertaco/Tavern/>) | ||
| 439 | * Thanks Pygmalion University for being awesome testers and suggesting cool features! | ||
| 440 | * Thanks oobabooga for compiling presets for TextGen | ||
| 441 | * KoboldAI Presets from KAI Lite: <https://lite.koboldai.net/> | ||
| 442 | * Noto Sans font by Google (OFL license) | 367 | * Noto Sans font by Google (OFL license) |
| 443 | * Icon theme by Font Awesome <https://fontawesome.com> (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) | 368 | * Icon theme by Font Awesome <https://fontawesome.com> (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) |
| 444 | * AI Horde client library by ZeldaFan0225: <https://github.com/ZeldaFan0225/ai_horde> | 369 | * Default content by @OtisAlejandro (Seraphina character and lorebook) and @kallmeflocc (10K Discord Users Celebratory Background) |
| 445 | * Linux startup script by AlpinDale | ||
| 446 | * Thanks paniphons for providing a FAQ document | ||
| 447 | * 10K Discord Users Celebratory Background by @kallmeflocc | ||
| 448 | * Default content (characters and lore books) provided by @OtisAlejandro, @RossAscends and @kallmeflocc | ||
| 449 | * Korean translation by @doloroushyeonse | ||
| 450 | * k_euler_a support for Horde by <https://github.com/Teashrock> | ||
| 451 | * Chinese translation by [@XXpE3](https://github.com/XXpE3), 中文 ISSUES 可以联系 @XXpE3 | ||
| 452 | * Docker guide by [@mrguymiah](https://github.com/mrguymiah) and [@Bronya-Rand](https://github.com/Bronya-Rand) | 370 | * Docker guide by [@mrguymiah](https://github.com/mrguymiah) and [@Bronya-Rand](https://github.com/Bronya-Rand) |
| 453 | 371 | ||
| 372 | ## Top Contributors | ||
| 373 | |||
| 374 | [](https://github.com/SillyTavern/SillyTavern/graphs/contributors) | ||
| 375 | |||
| 454 | <!-- LINK GROUP --> | 376 | <!-- LINK GROUP --> |
| 455 | [back-to-top]: https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square | 377 | [cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 |
| 456 | [cover]: https://github.com/SillyTavern/SillyTavern/assets/18619528/c2be4c3f-aada-4f64-87a3-ae35a68b61a4 | ||
| 457 | [discord-link]: https://discord.gg/sillytavern | 378 | [discord-link]: https://discord.gg/sillytavern |
| 458 | [discord-shield]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square | ||
| 459 | [discord-shield-badge]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge | 379 | [discord-shield-badge]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge |
| @@ -19,7 +19,7 @@ ENV NODE_ENV=production | |||
| 19 | COPY package*.json post-install.js ./ | 19 | COPY package*.json post-install.js ./ |
| 20 | RUN \ | 20 | RUN \ |
| 21 | echo "*** Install npm packages ***" && \ | 21 | echo "*** Install npm packages ***" && \ |
| 22 | npm i --no-audit --no-fund --quiet --omit=dev && npm cache clean --force | 22 | npm i --no-audit --no-fund --loglevel=error --no-progress --omit=dev && npm cache clean --force |
| 23 | 23 | ||
| 24 | # Bundle app source | 24 | # Bundle app source |
| 25 | COPY . ./ | 25 | COPY . ./ |
| @@ -1,7 +1,7 @@ | |||
| 1 | @echo off | 1 | @echo off |
| 2 | pushd %~dp0 | 2 | pushd %~dp0 |
| 3 | set NODE_ENV=production | 3 | set NODE_ENV=production |
| 4 | call npm install --no-audit --no-fund --quiet --omit=dev | 4 | call npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev |
| 5 | node server.js %* | 5 | node server.js %* |
| 6 | pause | 6 | pause |
| 7 | popd | 7 | popd |
| @@ -12,7 +12,7 @@ if %errorlevel% neq 0 ( | |||
| 12 | ) | 12 | ) |
| 13 | ) | 13 | ) |
| 14 | set NODE_ENV=production | 14 | set NODE_ENV=production |
| 15 | call npm install --no-audit --no-fund --quiet --omit=dev | 15 | call npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev |
| 16 | node server.js %* | 16 | node server.js %* |
| 17 | pause | 17 | pause |
| 18 | popd | 18 | popd |
| @@ -42,7 +42,7 @@ if NOT "!AUTO_SWITCH!"=="" ( | |||
| 42 | SET TARGET_BRANCH=release | 42 | SET TARGET_BRANCH=release |
| 43 | goto update | 43 | goto update |
| 44 | ) | 44 | ) |
| 45 | 45 | ||
| 46 | echo Auto-switching defined to stay on current branch | 46 | echo Auto-switching defined to stay on current branch |
| 47 | goto update | 47 | goto update |
| 48 | ) | 48 | ) |
| @@ -95,7 +95,7 @@ if %errorlevel% neq 0 ( | |||
| 95 | 95 | ||
| 96 | echo Installing npm packages and starting server | 96 | echo Installing npm packages and starting server |
| 97 | set NODE_ENV=production | 97 | set NODE_ENV=production |
| 98 | call npm install --no-audit --no-fund --quiet --omit=dev | 98 | call npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev |
| 99 | node server.js %* | 99 | node server.js %* |
| 100 | 100 | ||
| 101 | :end | 101 | :end |
| @@ -83,6 +83,8 @@ skipContentCheck: false | |||
| 83 | disableChatBackup: false | 83 | disableChatBackup: false |
| 84 | # Number of backups to keep for each chat and settings file | 84 | # Number of backups to keep for each chat and settings file |
| 85 | numberOfBackups: 50 | 85 | numberOfBackups: 50 |
| 86 | # Interval in milliseconds to throttle chat backups per user | ||
| 87 | chatBackupThrottleInterval: 10000 | ||
| 86 | # Allowed hosts for card downloads | 88 | # Allowed hosts for card downloads |
| 87 | whitelistImportDomains: | 89 | whitelistImportDomains: |
| 88 | - localhost | 90 | - localhost |
| @@ -108,6 +110,9 @@ enableExtensionsAutoUpdate: true | |||
| 108 | # Additional model tokenizers can be downloaded on demand. | 110 | # Additional model tokenizers can be downloaded on demand. |
| 109 | # Disabling will fallback to another locally available tokenizer. | 111 | # Disabling will fallback to another locally available tokenizer. |
| 110 | enableDownloadableTokenizers: true | 112 | enableDownloadableTokenizers: true |
| 113 | # Vector storage settings | ||
| 114 | vectors: | ||
| 115 | enableModelScopes: false | ||
| 111 | # Extension settings | 116 | # Extension settings |
| 112 | extras: | 117 | extras: |
| 113 | # Disables automatic model download from HuggingFace | 118 | # Disables automatic model download from HuggingFace |
| @@ -320,6 +320,26 @@ | |||
| 320 | "type": "novel_preset" | 320 | "type": "novel_preset" |
| 321 | }, | 321 | }, |
| 322 | { | 322 | { |
| 323 | "filename": "presets/novel/Erato-Dragonfruit.json", | ||
| 324 | "type": "novel_preset" | ||
| 325 | }, | ||
| 326 | { | ||
| 327 | "filename": "presets/novel/Erato-Golden Arrow.json", | ||
| 328 | "type": "novel_preset" | ||
| 329 | }, | ||
| 330 | { | ||
| 331 | "filename": "presets/novel/Erato-Shosetsu.json", | ||
| 332 | "type": "novel_preset" | ||
| 333 | }, | ||
| 334 | { | ||
| 335 | "filename": "presets/novel/Erato-Wilder.json", | ||
| 336 | "type": "novel_preset" | ||
| 337 | }, | ||
| 338 | { | ||
| 339 | "filename": "presets/novel/Erato-Zany Scribe.json", | ||
| 340 | "type": "novel_preset" | ||
| 341 | }, | ||
| 342 | { | ||
| 323 | "filename": "presets/textgen/Asterism.json", | 343 | "filename": "presets/textgen/Asterism.json", |
| 324 | "type": "textgen_preset" | 344 | "type": "textgen_preset" |
| 325 | }, | 345 | }, |
| @@ -468,10 +488,6 @@ | |||
| 468 | "type": "context" | 488 | "type": "context" |
| 469 | }, | 489 | }, |
| 470 | { | 490 | { |
| 471 | "filename": "presets/context/Alpaca-Roleplay.json", | ||
| 472 | "type": "context" | ||
| 473 | }, | ||
| 474 | { | ||
| 475 | "filename": "presets/context/Alpaca-Single-Turn.json", | 491 | "filename": "presets/context/Alpaca-Single-Turn.json", |
| 476 | "type": "context" | 492 | "type": "context" |
| 477 | }, | 493 | }, |
| @@ -512,10 +528,6 @@ | |||
| 512 | "type": "context" | 528 | "type": "context" |
| 513 | }, | 529 | }, |
| 514 | { | 530 | { |
| 515 | "filename": "presets/context/Mistral.json", | ||
| 516 | "type": "context" | ||
| 517 | }, | ||
| 518 | { | ||
| 519 | "filename": "presets/context/NovelAI.json", | 531 | "filename": "presets/context/NovelAI.json", |
| 520 | "type": "context" | 532 | "type": "context" |
| 521 | }, | 533 | }, |
| @@ -556,10 +568,6 @@ | |||
| 556 | "type": "instruct" | 568 | "type": "instruct" |
| 557 | }, | 569 | }, |
| 558 | { | 570 | { |
| 559 | "filename": "presets/instruct/Alpaca-Roleplay.json", | ||
| 560 | "type": "instruct" | ||
| 561 | }, | ||
| 562 | { | ||
| 563 | "filename": "presets/instruct/Alpaca-Single-Turn.json", | 571 | "filename": "presets/instruct/Alpaca-Single-Turn.json", |
| 564 | "type": "instruct" | 572 | "type": "instruct" |
| 565 | }, | 573 | }, |
| @@ -600,10 +608,6 @@ | |||
| 600 | "type": "instruct" | 608 | "type": "instruct" |
| 601 | }, | 609 | }, |
| 602 | { | 610 | { |
| 603 | "filename": "presets/instruct/Mistral.json", | ||
| 604 | "type": "instruct" | ||
| 605 | }, | ||
| 606 | { | ||
| 607 | "filename": "presets/instruct/OpenOrca-OpenChat.json", | 611 | "filename": "presets/instruct/OpenOrca-OpenChat.json", |
| 608 | "type": "instruct" | 612 | "type": "instruct" |
| 609 | }, | 613 | }, |
| @@ -686,5 +690,77 @@ | |||
| 686 | { | 690 | { |
| 687 | "filename": "presets/instruct/Gemma 2.json", | 691 | "filename": "presets/instruct/Gemma 2.json", |
| 688 | "type": "instruct" | 692 | "type": "instruct" |
| 693 | }, | ||
| 694 | { | ||
| 695 | "filename": "presets/sysprompt/Actor.json", | ||
| 696 | "type": "sysprompt" | ||
| 697 | }, | ||
| 698 | { | ||
| 699 | "filename": "presets/sysprompt/Assistant - Expert.json", | ||
| 700 | "type": "sysprompt" | ||
| 701 | }, | ||
| 702 | { | ||
| 703 | "filename": "presets/sysprompt/Assistant - Simple.json", | ||
| 704 | "type": "sysprompt" | ||
| 705 | }, | ||
| 706 | { | ||
| 707 | "filename": "presets/sysprompt/Chain of Thought.json", | ||
| 708 | "type": "sysprompt" | ||
| 709 | }, | ||
| 710 | { | ||
| 711 | "filename": "presets/sysprompt/Roleplay - Detailed.json", | ||
| 712 | "type": "sysprompt" | ||
| 713 | }, | ||
| 714 | { | ||
| 715 | "filename": "presets/sysprompt/Roleplay - Immersive.json", | ||
| 716 | "type": "sysprompt" | ||
| 717 | }, | ||
| 718 | { | ||
| 719 | "filename": "presets/sysprompt/Roleplay - Simple.json", | ||
| 720 | "type": "sysprompt" | ||
| 721 | }, | ||
| 722 | { | ||
| 723 | "filename": "presets/sysprompt/Text Adventure.json", | ||
| 724 | "type": "sysprompt" | ||
| 725 | }, | ||
| 726 | { | ||
| 727 | "filename": "presets/sysprompt/Writer - Creative.json", | ||
| 728 | "type": "sysprompt" | ||
| 729 | }, | ||
| 730 | { | ||
| 731 | "filename": "presets/sysprompt/Writer - Realistic.json", | ||
| 732 | "type": "sysprompt" | ||
| 733 | }, | ||
| 734 | { | ||
| 735 | "filename": "presets/sysprompt/Blank.json", | ||
| 736 | "type": "sysprompt" | ||
| 737 | }, | ||
| 738 | { | ||
| 739 | "filename": "presets/sysprompt/Neutral - Chat.json", | ||
| 740 | "type": "sysprompt" | ||
| 741 | }, | ||
| 742 | { | ||
| 743 | "filename": "presets/instruct/Mistral V1.json", | ||
| 744 | "type": "instruct" | ||
| 745 | }, | ||
| 746 | { | ||
| 747 | "filename": "presets/context/Mistral V1.json", | ||
| 748 | "type": "context" | ||
| 749 | }, | ||
| 750 | { | ||
| 751 | "filename": "presets/instruct/Mistral V2 & V3.json", | ||
| 752 | "type": "instruct" | ||
| 753 | }, | ||
| 754 | { | ||
| 755 | "filename": "presets/context/Mistral V2 & V3.json", | ||
| 756 | "type": "context" | ||
| 757 | }, | ||
| 758 | { | ||
| 759 | "filename": "presets/instruct/Mistral V3-Tekken.json", | ||
| 760 | "type": "instruct" | ||
| 761 | }, | ||
| 762 | { | ||
| 763 | "filename": "presets/context/Mistral V3-Tekken.json", | ||
| 764 | "type": "context" | ||
| 689 | } | 765 | } |
| 690 | ] | 766 | ] |
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": false, | 7 | "always_force_name2": false, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": true, | 9 | "single_line": true, |
| 11 | "name": "Adventure" | 10 | "name": "Adventure" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -1,12 +0,0 @@ | |||
| 1 | { | ||
| 2 | "story_string": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.\n\n{{#if system}}{{system}}\n\n{{/if}}### Input:\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}\n\n", | ||
| 3 | "example_separator": "### New Roleplay:", | ||
| 4 | "chat_start": "### New Roleplay:", | ||
| 5 | "use_stop_strings": false, | ||
| 6 | "allow_jailbreak": false, | ||
| 7 | "always_force_name2": true, | ||
| 8 | "trim_sentences": false, | ||
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | ||
| 11 | "name": "Alpaca-Roleplay" | ||
| 12 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": false, | 7 | "always_force_name2": false, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Alpaca-Single-Turn" | 10 | "name": "Alpaca-Single-Turn" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Alpaca" | 10 | "name": "Alpaca" |
| 12 | } | 11 | } |
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "ChatML-Names" | 10 | "name": "ChatML-Names" |
| 12 | } | 11 | } |
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "ChatML" | 10 | "name": "ChatML" |
| 12 | } | 11 | } |
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Command R" | 10 | "name": "Command R" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Default" | 10 | "name": "Default" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": false, | 7 | "always_force_name2": false, |
| 8 | "trim_sentences": true, | 8 | "trim_sentences": true, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "DreamGen Role-Play V1 ChatML" | 10 | "name": "DreamGen Role-Play V1 ChatML" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": false, | 7 | "always_force_name2": false, |
| 8 | "trim_sentences": true, | 8 | "trim_sentences": true, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "DreamGen Role-Play V1 Llama3" | 10 | "name": "DreamGen Role-Play V1 Llama3" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Gemma 2" | 10 | "name": "Gemma 2" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -1,12 +1,11 @@ | |||
| 1 | { | 1 | { |
| 2 | "story_string": "### Instruction:\nWrite {{char}}'s next reply in this roleplay with {{user}}. Use the provided character sheet and example dialogue for formatting direction and character speech patterns.\n\n{{#if system}}{{system}}\n\n{{/if}}### Character Sheet:\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", | 2 | "story_string": "### Instruction:\n{{#if system}}{{system}}\n\n{{/if}}### Character Sheet:\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", |
| 3 | "example_separator": "### Example:", | 3 | "example_separator": "### Example:", |
| 4 | "chat_start": "### START ROLEPLAY:", | 4 | "chat_start": "### START ROLEPLAY:", |
| 5 | "use_stop_strings": false, | 5 | "use_stop_strings": false, |
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Libra-32B" | 10 | "name": "Libra-32B" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Lightning 1.1" | 10 | "name": "Lightning 1.1" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Llama 2 Chat" | 10 | "name": "Llama 2 Chat" |
| 12 | } | 11 | } |
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Llama 3 Instruct" | 10 | "name": "Llama 3 Instruct" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Llama-3-Instruct-Names" | 10 | "name": "Llama-3-Instruct-Names" |
| 12 | } | 11 | } |
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Minimalist" | 10 | "name": "Minimalist" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -0,0 +1,11 @@ | |||
| 1 | { | ||
| 2 | "story_string": " [INST] {{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}} [/INST] Understood.</s>", | ||
| 3 | "example_separator": "", | ||
| 4 | "chat_start": "", | ||
| 5 | "use_stop_strings": false, | ||
| 6 | "allow_jailbreak": false, | ||
| 7 | "always_force_name2": true, | ||
| 8 | "trim_sentences": false, | ||
| 9 | "single_line": false, | ||
| 10 | "name": "Mistral V1" | ||
| 11 | } | ||
| @@ -1,12 +1,11 @@ | |||
| 1 | { | 1 | { |
| 2 | "story_string": "[INST] {{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}} [/INST]", | 2 | "story_string": "[INST] {{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}[/INST] Understood.</s>", |
| 3 | "example_separator": "Examples:", | 3 | "example_separator": "", |
| 4 | "chat_start": "", | 4 | "chat_start": "", |
| 5 | "use_stop_strings": false, | 5 | "use_stop_strings": false, |
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Mistral" | 10 | "name": "Mistral V2 & V3" |
| 12 | } | 11 | } |
| @@ -0,0 +1,11 @@ | |||
| 1 | { | ||
| 2 | "story_string": "[INST]{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}[/INST]Understood.</s>", | ||
| 3 | "example_separator": "", | ||
| 4 | "chat_start": "", | ||
| 5 | "use_stop_strings": false, | ||
| 6 | "allow_jailbreak": false, | ||
| 7 | "always_force_name2": true, | ||
| 8 | "trim_sentences": false, | ||
| 9 | "single_line": false, | ||
| 10 | "name": "Mistral V3-Tekken" | ||
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "NovelAI" | 10 | "name": "NovelAI" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "OldDefault" | 10 | "name": "OldDefault" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Phi" | 10 | "name": "Phi" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Pygmalion" | 10 | "name": "Pygmalion" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Story" | 10 | "name": "Story" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "Synthia" | 10 | "name": "Synthia" |
| 12 | } | 11 | } |
| @@ -6,7 +6,6 @@ | |||
| 6 | "allow_jailbreak": false, | 6 | "allow_jailbreak": false, |
| 7 | "always_force_name2": true, | 7 | "always_force_name2": true, |
| 8 | "trim_sentences": false, | 8 | "trim_sentences": false, |
| 9 | "include_newline": false, | ||
| 10 | "single_line": false, | 9 | "single_line": false, |
| 11 | "name": "simple-proxy-for-tavern" | 10 | "name": "simple-proxy-for-tavern" |
| 12 | } | ||
| 12 | \ No newline at end of file | \ No newline at end of file | |
| 11 | } | ||
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "[Enter Adventure Mode. Narrate the story based on {{user}}'s dialogue and actions after \">\". Describe the surroundings in vivid detail. Be detailed, creative, verbose, and proactive. Move the story forward by introducing fantasy elements and interesting characters.]", | ||
| 3 | "input_sequence": "", | 2 | "input_sequence": "", |
| 4 | "output_sequence": "", | 3 | "output_sequence": "", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "none", |
| 11 | "names_force_groups": false, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,24 +0,0 @@ | |||
| 1 | { | ||
| 2 | "system_prompt": "Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions.", | ||
| 3 | "input_sequence": "### Instruction:", | ||
| 4 | "output_sequence": "### Response:", | ||
| 5 | "last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):", | ||
| 6 | "system_sequence": "### Input:", | ||
| 7 | "stop_sequence": "", | ||
| 8 | "wrap": true, | ||
| 9 | "macro": true, | ||
| 10 | "names": true, | ||
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | ||
| 13 | "system_sequence_prefix": "", | ||
| 14 | "system_sequence_suffix": "", | ||
| 15 | "first_output_sequence": "", | ||
| 16 | "skip_examples": false, | ||
| 17 | "output_suffix": "\n\n", | ||
| 18 | "input_suffix": "\n\n", | ||
| 19 | "system_suffix": "\n\n", | ||
| 20 | "user_alignment_message": "", | ||
| 21 | "system_same_as_user": false, | ||
| 22 | "last_system_sequence": "", | ||
| 23 | "name": "Alpaca-Roleplay" | ||
| 24 | } | ||
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Write {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\nWrite 1 reply only, italicize actions, and avoid quotation marks. Use markdown. Be proactive, creative, and drive the plot and conversation forward. Include dialog as well as narration.", | ||
| 3 | "input_sequence": "", | 2 | "input_sequence": "", |
| 4 | "output_sequence": "", | 3 | "output_sequence": "", |
| 5 | "last_output_sequence": "\n### Response:", | 4 | "last_output_sequence": "\n### Response:", |
| @@ -7,12 +6,11 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| 15 | "first_output_sequence": "<START OF ROLEPLAY>", | 13 | "first_output_sequence": "<START OF CHAT>", |
| 16 | "skip_examples": false, | 14 | "skip_examples": false, |
| 17 | "output_suffix": "", | 15 | "output_suffix": "", |
| 18 | "input_suffix": "", | 16 | "input_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n", | ||
| 3 | "input_sequence": "### Instruction:", | 2 | "input_sequence": "### Instruction:", |
| 4 | "output_sequence": "### Response:", | 3 | "output_sequence": "### Response:", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.", | ||
| 3 | "input_sequence": "<|im_start|>[{{name}}]", | 2 | "input_sequence": "<|im_start|>[{{name}}]", |
| 4 | "output_sequence": "<|im_start|>[{{name}}]", | 3 | "output_sequence": "<|im_start|>[{{name}}]", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "<|im_end|>", | 6 | "stop_sequence": "<|im_end|>", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "none", |
| 11 | "names_force_groups": false, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.", | ||
| 3 | "input_sequence": "<|im_start|>user", | 2 | "input_sequence": "<|im_start|>user", |
| 4 | "output_sequence": "<|im_start|>assistant", | 3 | "output_sequence": "<|im_start|>assistant", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "<|im_end|>", | 6 | "stop_sequence": "<|im_end|>", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": true, | 9 | "names_behavior": "always", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.", | ||
| 3 | "input_sequence": "<|START_OF_TURN_TOKEN|><|USER_TOKEN|>", | 2 | "input_sequence": "<|START_OF_TURN_TOKEN|><|USER_TOKEN|>", |
| 4 | "output_sequence": "<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>", | 3 | "output_sequence": "<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>", |
| 5 | "first_output_sequence": "", | 4 | "first_output_sequence": "", |
| @@ -9,8 +8,7 @@ | |||
| 9 | "stop_sequence": "<|END_OF_TURN_TOKEN|>", | 8 | "stop_sequence": "<|END_OF_TURN_TOKEN|>", |
| 10 | "wrap": false, | 9 | "wrap": false, |
| 11 | "macro": true, | 10 | "macro": true, |
| 12 | "names": true, | 11 | "names_behavior": "always", |
| 13 | "names_force_groups": true, | ||
| 14 | "activation_regex": "", | 12 | "activation_regex": "", |
| 15 | "skip_examples": false, | 13 | "skip_examples": false, |
| 16 | "output_suffix": "<|END_OF_TURN_TOKEN|>", | 14 | "output_suffix": "<|END_OF_TURN_TOKEN|>", |
| @@ -21,4 +19,4 @@ | |||
| 21 | "last_system_sequence": "", | 19 | "last_system_sequence": "", |
| 22 | "system_same_as_user": false, | 20 | "system_same_as_user": false, |
| 23 | "name": "Command R" | 21 | "name": "Command R" |
| 24 | } | ||
| 24 | \ No newline at end of file | \ No newline at end of file | |
| 22 | } | ||
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below.", | ||
| 3 | "input_sequence": "\n<|im_start|>text names= {{name}}\n", | 2 | "input_sequence": "\n<|im_start|>text names= {{name}}\n", |
| 4 | "output_sequence": "\n<|im_start|>text names= {{name}}\n", | 3 | "output_sequence": "\n<|im_start|>text names= {{name}}\n", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "\n<|im_start|>", | 6 | "stop_sequence": "\n<|im_start|>", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "none", |
| 11 | "names_force_groups": false, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below.", | ||
| 3 | "input_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{user}}<|end_header_id|>\n\n", | 2 | "input_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{user}}<|end_header_id|>\n\n", |
| 4 | "output_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{char}}<|end_header_id|>\n\n", | 3 | "output_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{char}}<|end_header_id|>\n\n", |
| 5 | "first_output_sequence": "", | 4 | "first_output_sequence": "", |
| @@ -10,9 +9,8 @@ | |||
| 10 | "separator_sequence": "", | 9 | "separator_sequence": "", |
| 11 | "wrap": false, | 10 | "wrap": false, |
| 12 | "macro": true, | 11 | "macro": true, |
| 13 | "names": false, | 12 | "names_behavior": "none", |
| 14 | "names_force_groups": false, | ||
| 15 | "activation_regex": "", | 13 | "activation_regex": "", |
| 16 | "skip_examples": false, | 14 | "skip_examples": false, |
| 17 | "name": "DreamGen Role-Play V1 Llama3" | 15 | "name": "DreamGen Role-Play V1 Llama3" |
| 18 | } | ||
| 18 | \ No newline at end of file | \ No newline at end of file | |
| 16 | } | ||
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Continue writing this story and portray characters realistically.", | ||
| 3 | "input_sequence": "<start_of_turn>user", | 2 | "input_sequence": "<start_of_turn>user", |
| 4 | "output_sequence": "<start_of_turn>model", | 3 | "output_sequence": "<start_of_turn>model", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "<end_of_turn>", | 6 | "stop_sequence": "<end_of_turn>", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "none", |
| 11 | "names_force_groups": false, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Write {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n", | ||
| 3 | "input_sequence": "USER: ", | 2 | "input_sequence": "USER: ", |
| 4 | "output_sequence": "GPT: ", | 3 | "output_sequence": "GPT: ", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "BEGINNING OF CONVERSATION: ", | 11 | "system_sequence_prefix": "BEGINNING OF CONVERSATION: ", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Avoid repetition, don't loop. Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions.", | ||
| 3 | "input_sequence": "", | 2 | "input_sequence": "", |
| 4 | "output_sequence": "", | 3 | "output_sequence": "", |
| 5 | "last_output_sequence": "\n### Response:", | 4 | "last_output_sequence": "\n### Response:", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": true, | 9 | "names_behavior": "always", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\n### Instruction:\nTake the role of {{char}} in a play that leaves a lasting impression on {{user}}. Write {{char}}'s next reply.\nNever skip or gloss over {{char}}’s actions. Progress the scene at a naturally slow pace.\n\n", | ||
| 3 | "input_sequence": "### Instruction:", | 2 | "input_sequence": "### Instruction:", |
| 4 | "output_sequence": "### Response: (length = unlimited)", | 3 | "output_sequence": "### Response: (length = unlimited)", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.", | ||
| 3 | "input_sequence": "[INST] ", | 2 | "input_sequence": "[INST] ", |
| 4 | "output_sequence": "", | 3 | "output_sequence": "", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "You are an expert actor that can fully immerse yourself into any role given. You do not break character for any reason, even if someone tries addressing you as an AI or language model. Currently your role is {{char}}, which is described in detail below. As {{char}}, continue the exchange with {{user}}.", | ||
| 3 | "input_sequence": "<|start_header_id|>user<|end_header_id|>\n\n", | 2 | "input_sequence": "<|start_header_id|>user<|end_header_id|>\n\n", |
| 4 | "output_sequence": "<|start_header_id|>assistant<|end_header_id|>\n\n", | 3 | "output_sequence": "<|start_header_id|>assistant<|end_header_id|>\n\n", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "<|eot_id|>", | 6 | "stop_sequence": "<|eot_id|>", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": true, | 9 | "names_behavior": "always", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "You are an expert actor that can fully immerse yourself into any role given. You do not break character for any reason, even if someone tries addressing you as an AI or language model. Currently your role is {{char}}, which is described in detail below. As {{char}}, continue the exchange with {{user}}.", | ||
| 3 | "input_sequence": "<|start_header_id|>[{{name}}]<|end_header_id|>\n\n", | 2 | "input_sequence": "<|start_header_id|>[{{name}}]<|end_header_id|>\n\n", |
| 4 | "output_sequence": "<|start_header_id|>[{{name}}]<|end_header_id|>\n\n", | 3 | "output_sequence": "<|start_header_id|>[{{name}}]<|end_header_id|>\n\n", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "<|eot_id|>", | 6 | "stop_sequence": "<|eot_id|>", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "none", |
| 11 | "names_force_groups": false, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Enter roleplay mode. You must act as {{char}}, whose persona follows:", | ||
| 3 | "input_sequence": "<|user|>", | 2 | "input_sequence": "<|user|>", |
| 4 | "output_sequence": "<|model|>", | 3 | "output_sequence": "<|model|>", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "</s>", | 6 | "stop_sequence": "</s>", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "<|system|>", | 11 | "system_sequence_prefix": "<|system|>", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -0,0 +1,22 @@ | |||
| 1 | { | ||
| 2 | "input_sequence": " [INST] ", | ||
| 3 | "output_sequence": " [/INST] ", | ||
| 4 | "last_output_sequence": " [/INST]", | ||
| 5 | "system_sequence": "", | ||
| 6 | "stop_sequence": "", | ||
| 7 | "wrap": false, | ||
| 8 | "macro": true, | ||
| 9 | "names_behavior": "always", | ||
| 10 | "activation_regex": "", | ||
| 11 | "system_sequence_prefix": "", | ||
| 12 | "system_sequence_suffix": "", | ||
| 13 | "first_output_sequence": "", | ||
| 14 | "skip_examples": false, | ||
| 15 | "output_suffix": "</s>", | ||
| 16 | "input_suffix": "", | ||
| 17 | "system_suffix": "", | ||
| 18 | "user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.", | ||
| 19 | "system_same_as_user": true, | ||
| 20 | "last_system_sequence": "", | ||
| 21 | "name": "Mistral V1" | ||
| 22 | } | ||
| @@ -1,24 +1,22 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.", | ||
| 3 | "input_sequence": "[INST] ", | 2 | "input_sequence": "[INST] ", |
| 4 | "output_sequence": "", | 3 | "output_sequence": "[/INST] ", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "[/INST]", |
| 6 | "system_sequence": "", | 5 | "system_sequence": "", |
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": true, | 9 | "names_behavior": "always", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| 15 | "first_output_sequence": "", | 13 | "first_output_sequence": "", |
| 16 | "skip_examples": false, | 14 | "skip_examples": false, |
| 17 | "output_suffix": "\n", | 15 | "output_suffix": "</s>", |
| 18 | "input_suffix": " [/INST]\n", | 16 | "input_suffix": "", |
| 19 | "system_suffix": "", | 17 | "system_suffix": "", |
| 20 | "user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.", | 18 | "user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.", |
| 21 | "system_same_as_user": true, | 19 | "system_same_as_user": true, |
| 22 | "last_system_sequence": "", | 20 | "last_system_sequence": "", |
| 23 | "name": "Mistral" | 21 | "name": "Mistral V2 & V3" |
| 24 | } | 22 | } |
| @@ -0,0 +1,22 @@ | |||
| 1 | { | ||
| 2 | "input_sequence": "[INST]", | ||
| 3 | "output_sequence": "[/INST]", | ||
| 4 | "last_output_sequence": "", | ||
| 5 | "system_sequence": "", | ||
| 6 | "stop_sequence": "", | ||
| 7 | "wrap": false, | ||
| 8 | "macro": true, | ||
| 9 | "names_behavior": "always", | ||
| 10 | "activation_regex": "", | ||
| 11 | "system_sequence_prefix": "", | ||
| 12 | "system_sequence_suffix": "", | ||
| 13 | "first_output_sequence": "", | ||
| 14 | "skip_examples": false, | ||
| 15 | "output_suffix": "</s>", | ||
| 16 | "input_suffix": "", | ||
| 17 | "system_suffix": "", | ||
| 18 | "user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.", | ||
| 19 | "system_same_as_user": true, | ||
| 20 | "last_system_sequence": "", | ||
| 21 | "name": "Mistral V3-Tekken" | ||
| 22 | } | ||
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "You are a helpful assistant. Please answer truthfully and write out your thinking step by step to be sure you get the right answer. If you make a mistake or encounter an error in your thinking, say so out loud and attempt to correct it. If you don't know or aren't sure about something, say so clearly. You will act as a professional logician, mathematician, and physicist. You will also act as the most appropriate type of expert to answer any particular question or solve the relevant problem; state which expert type your are, if so. Also think of any particular named expert that would be ideal to answer the relevant question or solve the relevant problem; name and act as them, if appropriate.\n", | ||
| 3 | "input_sequence": "\nUser: ", | 2 | "input_sequence": "\nUser: ", |
| 4 | "output_sequence": "\nAssistant: ", | 3 | "output_sequence": "\nAssistant: ", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.", | ||
| 3 | "input_sequence": "<|user|>\n", | 2 | "input_sequence": "<|user|>\n", |
| 4 | "output_sequence": "<|assistant|>\n", | 3 | "output_sequence": "<|assistant|>\n", |
| 5 | "first_output_sequence": "", | 4 | "first_output_sequence": "", |
| @@ -9,8 +8,7 @@ | |||
| 9 | "stop_sequence": "<|end|>", | 8 | "stop_sequence": "<|end|>", |
| 10 | "wrap": false, | 9 | "wrap": false, |
| 11 | "macro": true, | 10 | "macro": true, |
| 12 | "names": true, | 11 | "names_behavior": "always", |
| 13 | "names_force_groups": true, | ||
| 14 | "activation_regex": "", | 12 | "activation_regex": "", |
| 15 | "skip_examples": false, | 13 | "skip_examples": false, |
| 16 | "output_suffix": "<|end|>\n", | 14 | "output_suffix": "<|end|>\n", |
| @@ -21,4 +19,4 @@ | |||
| 21 | "last_system_sequence": "", | 19 | "last_system_sequence": "", |
| 22 | "system_same_as_user": false, | 20 | "system_same_as_user": false, |
| 23 | "name": "Phi" | 21 | "name": "Phi" |
| 24 | } | ||
| 24 | \ No newline at end of file | \ No newline at end of file | |
| 22 | } | ||
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Enter RP mode. You shall reply to {{user}} while staying in character. Your responses must be detailed, creative, immersive, and drive the scenario forward. You will follow {{char}}'s persona.", | ||
| 3 | "input_sequence": "<|user|>", | 2 | "input_sequence": "<|user|>", |
| 4 | "output_sequence": "<|model|>", | 3 | "output_sequence": "<|model|>", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "<|user|>", | 6 | "stop_sequence": "<|user|>", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": true, | 9 | "names_behavior": "always", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "<|system|>", | 11 | "system_sequence_prefix": "<|system|>", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "", | ||
| 3 | "input_sequence": "", | 2 | "input_sequence": "", |
| 4 | "output_sequence": "", | 3 | "output_sequence": "", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "none", |
| 11 | "names_force_groups": false, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Elaborate on the topic using a Tree of Thoughts and backtrack when necessary to construct a clear, cohesive Chain of Thought reasoning. Always answer without hesitation.", | ||
| 3 | "input_sequence": "USER: ", | 2 | "input_sequence": "USER: ", |
| 4 | "output_sequence": "ASSISTANT: ", | 3 | "output_sequence": "ASSISTANT: ", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "SYSTEM: ", | 11 | "system_sequence_prefix": "SYSTEM: ", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n", | ||
| 3 | "input_sequence": "### Human:", | 2 | "input_sequence": "### Human:", |
| 4 | "output_sequence": "### Assistant:", | 3 | "output_sequence": "### Assistant:", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n", | ||
| 3 | "input_sequence": "\nUSER: ", | 2 | "input_sequence": "\nUSER: ", |
| 4 | "output_sequence": "\nASSISTANT: ", | 3 | "output_sequence": "\nASSISTANT: ", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": false, | 7 | "wrap": false, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "BEGINNING OF CONVERSATION:", | 11 | "system_sequence_prefix": "BEGINNING OF CONVERSATION:", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.\n\nWrite {{char}}'s next detailed reply in a fictional roleplay chat between {{user}} and {{char}}.", | ||
| 3 | "input_sequence": "USER: ", | 2 | "input_sequence": "USER: ", |
| 4 | "output_sequence": "ASSISTANT: ", | 3 | "output_sequence": "ASSISTANT: ", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "Write {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n", | ||
| 3 | "input_sequence": "", | 2 | "input_sequence": "", |
| 4 | "output_sequence": "### Response:", | 3 | "output_sequence": "### Response:", |
| 5 | "last_output_sequence": "", | 4 | "last_output_sequence": "", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "force", |
| 11 | "names_force_groups": true, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -1,5 +1,4 @@ | |||
| 1 | { | 1 | { |
| 2 | "system_prompt": "[System note: Write one reply only. Do not decide what {{user}} says or does. Write at least one paragraph, up to four. Be descriptive and immersive, providing vivid details about {{char}}'s actions, emotions, and the environment. Write with a high degree of complexity and burstiness. Do not repeat this message.]", | ||
| 3 | "input_sequence": "### Instruction:\n#### {{name}}:", | 2 | "input_sequence": "### Instruction:\n#### {{name}}:", |
| 4 | "output_sequence": "### Response:\n#### {{name}}:", | 3 | "output_sequence": "### Response:\n#### {{name}}:", |
| 5 | "last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):\n#### {{name}}:", | 4 | "last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):\n#### {{name}}:", |
| @@ -7,8 +6,7 @@ | |||
| 7 | "stop_sequence": "", | 6 | "stop_sequence": "", |
| 8 | "wrap": true, | 7 | "wrap": true, |
| 9 | "macro": true, | 8 | "macro": true, |
| 10 | "names": false, | 9 | "names_behavior": "none", |
| 11 | "names_force_groups": false, | ||
| 12 | "activation_regex": "", | 10 | "activation_regex": "", |
| 13 | "system_sequence_prefix": "", | 11 | "system_sequence_prefix": "", |
| 14 | "system_sequence_suffix": "", | 12 | "system_sequence_suffix": "", |
| @@ -14,7 +14,10 @@ | |||
| 14 | "use_cache": false, | 14 | "use_cache": false, |
| 15 | "return_full_text": false, | 15 | "return_full_text": false, |
| 16 | "prefix": "vanilla", | 16 | "prefix": "vanilla", |
| 17 | "cfg_scale": 1, | ||
| 18 | "phrase_rep_pen": "medium", | 17 | "phrase_rep_pen": "medium", |
| 19 | "max_context": 7800 | 18 | "max_context": 7800, |
| 19 | "min_p": 0, | ||
| 20 | "math1_temp": 1, | ||
| 21 | "math1_quad": 0, | ||
| 22 | "math1_quad_entropy_scale": 0 | ||
| 20 | } | 23 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | { | 1 | { |
| 2 | "order": [6, 0, 1, 2, 3], | 2 | "order": [0, 1, 2, 3], |
| 3 | "temperature": 1, | 3 | "temperature": 1, |
| 4 | "max_length": 150, | 4 | "max_length": 150, |
| 5 | "min_length": 1, | 5 | "min_length": 1, |
| @@ -14,6 +14,9 @@ | |||
| 14 | "return_full_text": false, | 14 | "return_full_text": false, |
| 15 | "prefix": "vanilla", | 15 | "prefix": "vanilla", |
| 16 | "phrase_rep_pen": "medium", | 16 | "phrase_rep_pen": "medium", |
| 17 | "cfg_scale": 1.55, | 17 | "max_context": 7800, |
| 18 | "max_context": 7800 | 18 | "min_p": 0, |
| 19 | "math1_temp": 1, | ||
| 20 | "math1_quad": 0, | ||
| 21 | "math1_quad_entropy_scale": 0 | ||
| 19 | } | 22 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | { | 1 | { |
| 2 | "order": [6, 2, 3, 1, 0], | 2 | "order": [2, 3, 1, 0], |
| 3 | "temperature": 1, | 3 | "temperature": 1, |
| 4 | "max_length": 150, | 4 | "max_length": 150, |
| 5 | "min_length": 1, | 5 | "min_length": 1, |
| @@ -15,6 +15,9 @@ | |||
| 15 | "return_full_text": false, | 15 | "return_full_text": false, |
| 16 | "prefix": "vanilla", | 16 | "prefix": "vanilla", |
| 17 | "phrase_rep_pen": "very_aggressive", | 17 | "phrase_rep_pen": "very_aggressive", |
| 18 | "cfg_scale": 1.3, | 18 | "max_context": 7800, |
| 19 | "max_context": 7800 | 19 | "min_p": 0, |
| 20 | "math1_temp": 1, | ||
| 21 | "math1_quad": 0, | ||
| 22 | "math1_quad_entropy_scale": 0 | ||
| 20 | } | 23 | } |
| @@ -15,7 +15,10 @@ | |||
| 15 | "use_cache": false, | 15 | "use_cache": false, |
| 16 | "return_full_text": false, | 16 | "return_full_text": false, |
| 17 | "prefix": "vanilla", | 17 | "prefix": "vanilla", |
| 18 | "cfg_scale": 1, | ||
| 19 | "phrase_rep_pen": "aggressive", | 18 | "phrase_rep_pen": "aggressive", |
| 20 | "max_context": 7800 | 19 | "max_context": 7800, |
| 20 | "min_p": 0, | ||
| 21 | "math1_temp": 1, | ||
| 22 | "math1_quad": 0, | ||
| 23 | "math1_quad_entropy_scale": 0 | ||
| 21 | } | 24 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | { | 1 | { |
| 2 | "order": [8, 6, 5, 0, 3], | 2 | "order": [8, 5, 0, 3], |
| 3 | "temperature": 0.9, | 3 | "temperature": 0.9, |
| 4 | "max_length": 150, | 4 | "max_length": 150, |
| 5 | "min_length": 1, | 5 | "min_length": 1, |
| @@ -15,6 +15,9 @@ | |||
| 15 | "return_full_text": false, | 15 | "return_full_text": false, |
| 16 | "prefix": "vanilla", | 16 | "prefix": "vanilla", |
| 17 | "phrase_rep_pen": "off", | 17 | "phrase_rep_pen": "off", |
| 18 | "cfg_scale": 1.48, | 18 | "max_context": 7800, |
| 19 | "max_context": 7800 | 19 | "min_p": 0, |
| 20 | "math1_temp": 1, | ||
| 21 | "math1_quad": 0, | ||
| 22 | "math1_quad_entropy_scale": 0 | ||
| 20 | } | 23 | } |
| @@ -15,7 +15,10 @@ | |||
| 15 | "use_cache": false, | 15 | "use_cache": false, |
| 16 | "return_full_text": false, | 16 | "return_full_text": false, |
| 17 | "prefix": "vanilla", | 17 | "prefix": "vanilla", |
| 18 | "cfg_scale": 1, | ||
| 19 | "phrase_rep_pen": "very_light", | 18 | "phrase_rep_pen": "very_light", |
| 20 | "max_context": 7800 | 19 | "max_context": 7800, |
| 20 | "min_p": 0, | ||
| 21 | "math1_temp": 1, | ||
| 22 | "math1_quad": 0, | ||
| 23 | "math1_quad_entropy_scale": 0 | ||
| 21 | } | 24 | } |
| @@ -0,0 +1,31 @@ | |||
| 1 | { | ||
| 2 | "max_context": 8000, | ||
| 3 | "temperature": 1.37, | ||
| 4 | "max_length": 150, | ||
| 5 | "min_length": 1, | ||
| 6 | "top_k": 0, | ||
| 7 | "top_p": 1, | ||
| 8 | "top_a": 0.1, | ||
| 9 | "typical_p": 0.875, | ||
| 10 | "tail_free_sampling": 0.87, | ||
| 11 | "repetition_penalty": 3.25, | ||
| 12 | "repetition_penalty_range": 6000, | ||
| 13 | "repetition_penalty_slope": 3.25, | ||
| 14 | "repetition_penalty_frequency": 0, | ||
| 15 | "repetition_penalty_presence": 0, | ||
| 16 | "phrase_rep_pen": "off", | ||
| 17 | "mirostat_lr": 0.2, | ||
| 18 | "mirostat_tau": 4, | ||
| 19 | "math1_temp": 0.9, | ||
| 20 | "math1_quad": 0.07, | ||
| 21 | "math1_quad_entropy_scale": -0.05, | ||
| 22 | "min_p": 0.035, | ||
| 23 | "order": [ | ||
| 24 | 0, | ||
| 25 | 5, | ||
| 26 | 9, | ||
| 27 | 10, | ||
| 28 | 8, | ||
| 29 | 4 | ||
| 30 | ] | ||
| 31 | } | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | { | ||
| 2 | "max_context": 8000, | ||
| 3 | "temperature": 1, | ||
| 4 | "max_length": 150, | ||
| 5 | "min_length": 1, | ||
| 6 | "top_k": 0, | ||
| 7 | "top_p": 0.995, | ||
| 8 | "top_a": 1, | ||
| 9 | "typical_p": 1, | ||
| 10 | "tail_free_sampling": 0.87, | ||
| 11 | "repetition_penalty": 1.5, | ||
| 12 | "repetition_penalty_range": 2240, | ||
| 13 | "repetition_penalty_slope": 1, | ||
| 14 | "repetition_penalty_frequency": 0, | ||
| 15 | "repetition_penalty_presence": 0, | ||
| 16 | "phrase_rep_pen": "light", | ||
| 17 | "mirostat_lr": 1, | ||
| 18 | "mirostat_tau": 0, | ||
| 19 | "math1_temp": 0.3, | ||
| 20 | "math1_quad": 0.19, | ||
| 21 | "math1_quad_entropy_scale": 0, | ||
| 22 | "min_p": 0, | ||
| 23 | "order": [ | ||
| 24 | 9, | ||
| 25 | 2 | ||
| 26 | ] | ||
| 27 | } | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | { | ||
| 2 | "max_context": 8000, | ||
| 3 | "temperature": 1, | ||
| 4 | "max_length": 150, | ||
| 5 | "min_length": 1, | ||
| 6 | "top_k": 50, | ||
| 7 | "top_p": 0.85, | ||
| 8 | "top_a": 1, | ||
| 9 | "typical_p": 1, | ||
| 10 | "tail_free_sampling": 0.895, | ||
| 11 | "repetition_penalty": 1.63, | ||
| 12 | "repetition_penalty_range": 1024, | ||
| 13 | "repetition_penalty_slope": 3.33, | ||
| 14 | "repetition_penalty_frequency": 0.0035, | ||
| 15 | "repetition_penalty_presence": 0, | ||
| 16 | "phrase_rep_pen": "medium", | ||
| 17 | "mirostat_lr": 1, | ||
| 18 | "mirostat_tau": 0, | ||
| 19 | "math1_temp": 0.3, | ||
| 20 | "math1_quad": 0.0645, | ||
| 21 | "math1_quad_entropy_scale": 0.05, | ||
| 22 | "min_p": 0.05, | ||
| 23 | "order": [ | ||
| 24 | 9, | ||
| 25 | 10 | ||
| 26 | ] | ||
| 27 | } | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | { | ||
| 2 | "max_context": 8000, | ||
| 3 | "temperature": 1, | ||
| 4 | "max_length": 150, | ||
| 5 | "min_length": 1, | ||
| 6 | "top_k": 300, | ||
| 7 | "top_p": 0.98, | ||
| 8 | "top_a": 0.004, | ||
| 9 | "typical_p": 0.96, | ||
| 10 | "tail_free_sampling": 0.96, | ||
| 11 | "repetition_penalty": 1.48, | ||
| 12 | "repetition_penalty_range": 2240, | ||
| 13 | "repetition_penalty_slope": 0.64, | ||
| 14 | "repetition_penalty_frequency": 0, | ||
| 15 | "repetition_penalty_presence": 0, | ||
| 16 | "phrase_rep_pen": "medium", | ||
| 17 | "mirostat_lr": 1, | ||
| 18 | "mirostat_tau": 0, | ||
| 19 | "math1_temp": -0.0485, | ||
| 20 | "math1_quad": 0.145, | ||
| 21 | "math1_quad_entropy_scale": 0, | ||
| 22 | "min_p": 0.02, | ||
| 23 | "order": [ | ||
| 24 | 9, | ||
| 25 | 10 | ||
| 26 | ] | ||
| 27 | } | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | { | ||
| 2 | "max_context": 8000, | ||
| 3 | "temperature": 1, | ||
| 4 | "max_length": 150, | ||
| 5 | "min_length": 1, | ||
| 6 | "top_k": 0, | ||
| 7 | "top_p": 0.99, | ||
| 8 | "top_a": 1, | ||
| 9 | "typical_p": 1, | ||
| 10 | "tail_free_sampling": 0.99, | ||
| 11 | "repetition_penalty": 1, | ||
| 12 | "repetition_penalty_range": 64, | ||
| 13 | "repetition_penalty_slope": 1, | ||
| 14 | "repetition_penalty_frequency": 0.75, | ||
| 15 | "repetition_penalty_presence": 1.5, | ||
| 16 | "phrase_rep_pen": "medium", | ||
| 17 | "mirostat_lr": 1, | ||
| 18 | "mirostat_tau": 1, | ||
| 19 | "math1_temp": -0.4, | ||
| 20 | "math1_quad": 0.6, | ||
| 21 | "math1_quad_entropy_scale": -0.1, | ||
| 22 | "min_p": 0.08, | ||
| 23 | "order": [ | ||
| 24 | 9, | ||
| 25 | 2 | ||
| 26 | ] | ||
| 27 | } | ||
| @@ -16,7 +16,10 @@ | |||
| 16 | "use_cache": false, | 16 | "use_cache": false, |
| 17 | "return_full_text": false, | 17 | "return_full_text": false, |
| 18 | "prefix": "vanilla", | 18 | "prefix": "vanilla", |
| 19 | "cfg_scale": 1, | ||
| 20 | "phrase_rep_pen": "very_light", | 19 | "phrase_rep_pen": "very_light", |
| 21 | "max_context": 7800 | 20 | "max_context": 7800, |
| 21 | "min_p": 0, | ||
| 22 | "math1_temp": 1, | ||
| 23 | "math1_quad": 0, | ||
| 24 | "math1_quad_entropy_scale": 0 | ||
| 22 | } | 25 | } |
| @@ -14,7 +14,10 @@ | |||
| 14 | "use_cache": false, | 14 | "use_cache": false, |
| 15 | "return_full_text": false, | 15 | "return_full_text": false, |
| 16 | "prefix": "vanilla", | 16 | "prefix": "vanilla", |
| 17 | "cfg_scale": 1, | ||
| 18 | "phrase_rep_pen": "off", | 17 | "phrase_rep_pen": "off", |
| 19 | "max_context": 7800 | 18 | "max_context": 7800, |
| 19 | "min_p": 0, | ||
| 20 | "math1_temp": 1, | ||
| 21 | "math1_quad": 0, | ||
| 22 | "math1_quad_entropy_scale": 0 | ||
| 20 | } | 23 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | { | 1 | { |
| 2 | "order": [6, 0, 8, 5, 3], | 2 | "order": [0, 8, 5, 3], |
| 3 | "temperature": 1.5, | 3 | "temperature": 1.5, |
| 4 | "max_length": 150, | 4 | "max_length": 150, |
| 5 | "min_length": 1, | 5 | "min_length": 1, |
| @@ -15,6 +15,9 @@ | |||
| 15 | "return_full_text": false, | 15 | "return_full_text": false, |
| 16 | "prefix": "vanilla", | 16 | "prefix": "vanilla", |
| 17 | "phrase_rep_pen": "very_aggressive", | 17 | "phrase_rep_pen": "very_aggressive", |
| 18 | "cfg_scale": 1.4, | 18 | "max_context": 7800, |
| 19 | "max_context": 7800 | 19 | "min_p": 0, |
| 20 | "math1_temp": 1, | ||
| 21 | "math1_quad": 0, | ||
| 22 | "math1_quad_entropy_scale": 0 | ||
| 20 | } | 23 | } |
| @@ -16,7 +16,10 @@ | |||
| 16 | "use_cache": false, | 16 | "use_cache": false, |
| 17 | "return_full_text": false, | 17 | "return_full_text": false, |
| 18 | "prefix": "vanilla", | 18 | "prefix": "vanilla", |
| 19 | "cfg_scale": 1, | ||
| 20 | "phrase_rep_pen": "very_light", | 19 | "phrase_rep_pen": "very_light", |
| 21 | "max_context": 7800 | 20 | "max_context": 7800, |
| 21 | "min_p": 0, | ||
| 22 | "math1_temp": 1, | ||
| 23 | "math1_quad": 0, | ||
| 24 | "math1_quad_entropy_scale": 0 | ||
| 22 | } | 25 | } |
| @@ -16,7 +16,10 @@ | |||
| 16 | "use_cache": false, | 16 | "use_cache": false, |
| 17 | "return_full_text": false, | 17 | "return_full_text": false, |
| 18 | "prefix": "vanilla", | 18 | "prefix": "vanilla", |
| 19 | "cfg_scale": 1, | ||
| 20 | "phrase_rep_pen": "very_light", | 19 | "phrase_rep_pen": "very_light", |
| 21 | "max_context": 7800 | 20 | "max_context": 7800, |
| 21 | "min_p": 0, | ||
| 22 | "math1_temp": 1, | ||
| 23 | "math1_quad": 0, | ||
| 24 | "math1_quad_entropy_scale": 0 | ||
| 22 | } | 25 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | { | 1 | { |
| 2 | "order": [6, 0, 4, 1, 2, 5, 3], | 2 | "order": [0, 4, 1, 2, 5, 3], |
| 3 | "temperature": 1.31, | 3 | "temperature": 1.31, |
| 4 | "max_length": 150, | 4 | "max_length": 150, |
| 5 | "min_length": 1, | 5 | "min_length": 1, |
| @@ -17,6 +17,9 @@ | |||
| 17 | "return_full_text": false, | 17 | "return_full_text": false, |
| 18 | "prefix": "vanilla", | 18 | "prefix": "vanilla", |
| 19 | "phrase_rep_pen": "medium", | 19 | "phrase_rep_pen": "medium", |
| 20 | "cfg_scale": 1.35, | 20 | "max_context": 7800, |
| 21 | "max_context": 7800 | 21 | "min_p": 0, |
| 22 | "math1_temp": 1, | ||
| 23 | "math1_quad": 0, | ||
| 24 | "math1_quad_entropy_scale": 0 | ||
| 22 | } | 25 | } |
| @@ -15,6 +15,9 @@ | |||
| 15 | "return_full_text": false, | 15 | "return_full_text": false, |
| 16 | "prefix": "vanilla", | 16 | "prefix": "vanilla", |
| 17 | "phrase_rep_pen": "medium", | 17 | "phrase_rep_pen": "medium", |
| 18 | "cfg_scale": 1.0, | 18 | "max_context": 7800, |
| 19 | "max_context": 7800 | 19 | "min_p": 0, |
| 20 | "math1_temp": 1, | ||
| 21 | "math1_quad": 0, | ||
| 22 | "math1_quad_entropy_scale": 0 | ||
| 20 | } | 23 | } |
| @@ -13,5 +13,9 @@ | |||
| 13 | "return_full_text": false, | 13 | "return_full_text": false, |
| 14 | "prefix": "vanilla", | 14 | "prefix": "vanilla", |
| 15 | "phrase_rep_pen": "medium", | 15 | "phrase_rep_pen": "medium", |
| 16 | "max_context": 7800 | 16 | "max_context": 7800, |
| 17 | "min_p": 0, | ||
| 18 | "math1_temp": 1, | ||
| 19 | "math1_quad": 0, | ||
| 20 | "math1_quad_entropy_scale": 0 | ||
| 17 | } | 21 | } |
| @@ -16,7 +16,10 @@ | |||
| 16 | "use_cache": false, | 16 | "use_cache": false, |
| 17 | "return_full_text": false, | 17 | "return_full_text": false, |
| 18 | "prefix": "vanilla", | 18 | "prefix": "vanilla", |
| 19 | "cfg_scale": 1, | ||
| 20 | "phrase_rep_pen": "very_light", | 19 | "phrase_rep_pen": "very_light", |
| 21 | "max_context": 7800 | 20 | "max_context": 7800, |
| 21 | "min_p": 0, | ||
| 22 | "math1_temp": 1, | ||
| 23 | "math1_quad": 0, | ||
| 24 | "math1_quad_entropy_scale": 0 | ||
| 22 | } | 25 | } |
| @@ -14,6 +14,9 @@ | |||
| 14 | "return_full_text": false, | 14 | "return_full_text": false, |
| 15 | "prefix": "vanilla", | 15 | "prefix": "vanilla", |
| 16 | "phrase_rep_pen": "aggressive", | 16 | "phrase_rep_pen": "aggressive", |
| 17 | "cfg_scale": 1.0, | 17 | "max_context": 7800, |
| 18 | "max_context": 7800 | 18 | "min_p": 0, |
| 19 | "math1_temp": 1, | ||
| 20 | "math1_quad": 0, | ||
| 21 | "math1_quad_entropy_scale": 0 | ||
| 19 | } | 22 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | { | 1 | { |
| 2 | "order": [6, 0, 5], | 2 | "order": [0, 5], |
| 3 | "temperature": 0.895, | 3 | "temperature": 0.895, |
| 4 | "max_length": 150, | 4 | "max_length": 150, |
| 5 | "min_length": 1, | 5 | "min_length": 1, |
| @@ -13,6 +13,9 @@ | |||
| 13 | "return_full_text": false, | 13 | "return_full_text": false, |
| 14 | "prefix": "vanilla", | 14 | "prefix": "vanilla", |
| 15 | "phrase_rep_pen": "aggressive", | 15 | "phrase_rep_pen": "aggressive", |
| 16 | "cfg_scale": 1.3, | 16 | "max_context": 7800, |
| 17 | "max_context": 7800 | 17 | "min_p": 0, |
| 18 | "math1_temp": 1, | ||
| 19 | "math1_quad": 0, | ||
| 20 | "math1_quad_entropy_scale": 0 | ||
| 18 | } | 21 | } |
| @@ -16,7 +16,10 @@ | |||
| 16 | "use_cache": false, | 16 | "use_cache": false, |
| 17 | "return_full_text": false, | 17 | "return_full_text": false, |
| 18 | "prefix": "vanilla", | 18 | "prefix": "vanilla", |
| 19 | "cfg_scale": 1, | ||
| 20 | "phrase_rep_pen": "very_light", | 19 | "phrase_rep_pen": "very_light", |
| 21 | "max_context": 7800 | 20 | "max_context": 7800, |
| 21 | "min_p": 0, | ||
| 22 | "math1_temp": 1, | ||
| 23 | "math1_quad": 0, | ||
| 24 | "math1_quad_entropy_scale": 0 | ||
| 22 | } | 25 | } |
| @@ -17,5 +17,9 @@ | |||
| 17 | "return_full_text": false, | 17 | "return_full_text": false, |
| 18 | "prefix": "vanilla", | 18 | "prefix": "vanilla", |
| 19 | "phrase_rep_pen": "very_aggressive", | 19 | "phrase_rep_pen": "very_aggressive", |
| 20 | "max_context": 7800 | 20 | "max_context": 7800, |
| 21 | "min_p": 0, | ||
| 22 | "math1_temp": 1, | ||
| 23 | "math1_quad": 0, | ||
| 24 | "math1_quad_entropy_scale": 0 | ||
| 21 | } | 25 | } |
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Actor", | ||
| 3 | "content": "You are an expert actor that can fully immerse yourself into any role given. You do not break character for any reason, even if someone tries addressing you as an AI or language model. Currently your role is {{char}}, which is described in detail below. As {{char}}, continue the exchange with {{user}}." | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Assistant - Expert", | ||
| 3 | "content": "You are a helpful assistant. Please answer truthfully and write out your thinking step by step to be sure you get the right answer. If you make a mistake or encounter an error in your thinking, say so out loud and attempt to correct it. If you don't know or aren't sure about something, say so clearly. You will act as a professional logician, mathematician, and physicist. You will also act as the most appropriate type of expert to answer any particular question or solve the relevant problem; state which expert type your are, if so. Also think of any particular named expert that would be ideal to answer the relevant question or solve the relevant problem; name and act as them, if appropriate." | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Assistant - Simple", | ||
| 3 | "content": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions." | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Blank", | ||
| 3 | "content": "" | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Chain of Thought", | ||
| 3 | "content": "Elaborate on the topic using a Tree of Thoughts and backtrack when necessary to construct a clear, cohesive Chain of Thought reasoning. Always answer without hesitation." | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Neutral - Chat", | ||
| 3 | "content": "Write {{char}}'s next reply in a fictional chat between {{char}} and {{user}}." | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Roleplay - Detailed", | ||
| 3 | "content": "Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions. Keep the story immersive and engaging." | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Roleplay - Immersive", | ||
| 3 | "content": "[System note: Write one reply only. Do not decide what {{user}} says or does. Write at least one paragraph, up to four. Be descriptive and immersive, providing vivid details about {{char}}'s actions, emotions, and the environment. Write with a high degree of complexity and burstiness. Do not repeat this message.]" | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Roleplay - Simple", | ||
| 3 | "content": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}." | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Text Adventure", | ||
| 3 | "content": "[Enter Adventure Mode. Narrate the story based on {{user}}'s dialogue and actions after \">\". Describe the surroundings in vivid detail. Be detailed, creative, verbose, and proactive. Move the story forward by introducing fantasy elements and interesting characters.]" | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Writer - Creative", | ||
| 3 | "content": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below." | ||
| 4 | } | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | { | ||
| 2 | "name": "Writer - Realistic", | ||
| 3 | "content": "Continue writing this story and portray characters realistically." | ||
| 4 | } | ||
| @@ -90,7 +90,6 @@ | |||
| 90 | "pin_examples": false, | 90 | "pin_examples": false, |
| 91 | "strip_examples": false, | 91 | "strip_examples": false, |
| 92 | "trim_sentences": false, | 92 | "trim_sentences": false, |
| 93 | "include_newline": false, | ||
| 94 | "always_force_name2": true, | 93 | "always_force_name2": true, |
| 95 | "user_prompt_bias": "", | 94 | "user_prompt_bias": "", |
| 96 | "show_user_prompt_bias": true, | 95 | "show_user_prompt_bias": true, |
| @@ -150,11 +149,9 @@ | |||
| 150 | "continue_on_send": false, | 149 | "continue_on_send": false, |
| 151 | "trim_spaces": true, | 150 | "trim_spaces": true, |
| 152 | "relaxed_api_urls": false, | 151 | "relaxed_api_urls": false, |
| 153 | "default_instruct": "", | ||
| 154 | "instruct": { | 152 | "instruct": { |
| 155 | "enabled": false, | 153 | "enabled": false, |
| 156 | "preset": "Alpaca", | 154 | "preset": "Alpaca", |
| 157 | "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n", | ||
| 158 | "input_sequence": "### Instruction:", | 155 | "input_sequence": "### Instruction:", |
| 159 | "output_sequence": "### Response:", | 156 | "output_sequence": "### Response:", |
| 160 | "last_output_sequence": "", | 157 | "last_output_sequence": "", |
| @@ -162,8 +159,7 @@ | |||
| 162 | "stop_sequence": "", | 159 | "stop_sequence": "", |
| 163 | "wrap": true, | 160 | "wrap": true, |
| 164 | "macro": true, | 161 | "macro": true, |
| 165 | "names": false, | 162 | "names_behavior": "force", |
| 166 | "names_force_groups": true, | ||
| 167 | "activation_regex": "", | 163 | "activation_regex": "", |
| 168 | "system_sequence_prefix": "", | 164 | "system_sequence_prefix": "", |
| 169 | "system_sequence_suffix": "", | 165 | "system_sequence_suffix": "", |
| @@ -175,7 +171,11 @@ | |||
| 175 | "user_alignment_message": "", | 171 | "user_alignment_message": "", |
| 176 | "system_same_as_user": false | 172 | "system_same_as_user": false |
| 177 | }, | 173 | }, |
| 178 | "default_context": "Default", | 174 | "sysprompt": { |
| 175 | "enabled": true, | ||
| 176 | "name": "Neutral - Chat", | ||
| 177 | "content": "Write {{char}}'s next reply in a fictional chat between {{char}} and {{user}}." | ||
| 178 | }, | ||
| 179 | "context": { | 179 | "context": { |
| 180 | "preset": "Default", | 180 | "preset": "Default", |
| 181 | "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", | 181 | "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", |
| @@ -235,7 +235,7 @@ | |||
| 235 | "lengthPenaltyStep": 0.1, | 235 | "lengthPenaltyStep": 0.1, |
| 236 | "memoryFrozen": false, | 236 | "memoryFrozen": false, |
| 237 | "source": "extras", | 237 | "source": "extras", |
| 238 | "prompt": "[Pause your roleplay. Summarize the most important facts and events that have happened in the chat so far. If a summary already exists in your memory, use that as a base and expand with new facts. Limit the summary to {{words}} words or less. Your response should include nothing but the summary.]", | 238 | "prompt": "Ignore previous instructions. Summarize the most important facts and events in the story so far. If a summary already exists in your memory, use that as a base and expand with new facts. Limit the summary to {{words}} words or less. Your response should include nothing but the summary.", |
| 239 | "promptWords": 200, | 239 | "promptWords": 200, |
| 240 | "promptMinWords": 25, | 240 | "promptMinWords": 25, |
| 241 | "promptMaxWords": 1000, | 241 | "promptMaxWords": 1000, |
| @@ -298,13 +298,13 @@ | |||
| 298 | "horde_karras": true, | 298 | "horde_karras": true, |
| 299 | "refine_mode": false, | 299 | "refine_mode": false, |
| 300 | "prompts": { | 300 | "prompts": { |
| 301 | "0": "[In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,']", | 301 | "0": "In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,'", |
| 302 | "1": "[Pause your roleplay and provide a detailed description of {{user}}'s physical appearance from the perspective of {{char}} in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,'. Ignore the rest of the story when crafting this description. Do not roleplay as {{char}} when writing this description, and do not attempt to continue the story.]", | 302 | "1": "Ignore previous instructions and provide a detailed description of {{user}}'s physical appearance from the perspective of {{char}} in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,'. Ignore the rest of the story when crafting this description. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.", |
| 303 | "2": "[Pause your roleplay and provide a detailed description for all of the following: a brief recap of recent events in the story, {{char}}'s appearance, and {{char}}'s surroundings. Do not roleplay while writing this description.]", | 303 | "2": "Ignore previous instructions and provide a detailed description for all of the following: a brief recap of recent events in the story, {{char}}'s appearance, and {{char}}'s surroundings. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.", |
| 304 | "3": "[Pause your roleplay and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not roleplay at all in your response. Do not continue the roleplay story.]", | 304 | "3": "Ignore previous instructions and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.", |
| 305 | "4": "[Pause your roleplay. Your next response must be formatted as a single comma-delimited list of concise keywords. The list will describe of the visual details included in the last chat message.\n\n Only mention characters by using pronouns ('he','his','she','her','it','its') or neutral nouns ('male', 'the man', 'female', 'the woman').\n\n Ignore non-visible things such as feelings, personality traits, thoughts, and spoken dialog.\n\n Add keywords in this precise order:\n a keyword to describe the location of the scene,\n a keyword to mention how many characters of each gender or type are present in the scene (minimum of two characters:\n {{user}} and {{char}}, example: '2 men ' or '1 man 1 woman ', '1 man 3 robots'),\n\n keywords to describe the relative physical positioning of the characters to each other (if a commonly known term for the positioning is known use it instead of describing the positioning in detail) + 'POV',\n\n a single keyword or phrase to describe the primary act taking place in the last chat message,\n\n keywords to describe {{char}}'s physical appearance and facial expression,\n keywords to describe {{char}}'s actions,\n keywords to describe {{user}}'s physical appearance and actions.\n\n If character actions involve direct physical interaction with another character, mention specifically which body parts interacting and how.\n\n A correctly formatted example response would be:\n '(location),(character list by gender),(primary action), (relative character position) POV, (character 1's description and actions), (character 2's description and actions)']", | 305 | "4": "Ignore previous instructions. Your next response must be formatted as a single comma-delimited list of concise keywords. The list will describe of the visual details included in the last chat message.\n\n Only mention characters by using pronouns ('he','his','she','her','it','its') or neutral nouns ('male', 'the man', 'female', 'the woman').\n\n Ignore non-visible things such as feelings, personality traits, thoughts, and spoken dialog.\n\n Add keywords in this precise order:\n a keyword to describe the location of the scene,\n a keyword to mention how many characters of each gender or type are present in the scene (minimum of two characters:\n {{user}} and {{char}}, example: '2 men ' or '1 man 1 woman ', '1 man 3 robots'),\n\n keywords to describe the relative physical positioning of the characters to each other (if a commonly known term for the positioning is known use it instead of describing the positioning in detail) + 'POV',\n\n a single keyword or phrase to describe the primary act taking place in the last chat message,\n\n keywords to describe {{char}}'s physical appearance and facial expression,\n keywords to describe {{char}}'s actions,\n keywords to describe {{user}}'s physical appearance and actions.\n\n If character actions involve direct physical interaction with another character, mention specifically which body parts interacting and how.\n\n A correctly formatted example response would be:\n '(location),(character list by gender),(primary action), (relative character position) POV, (character 1's description and actions), (character 2's description and actions)'", |
| 306 | "5": "[In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, facial features and expressions, occupation, hair and hair accessories (if any), what they are wearing on their upper body (if anything). Do not describe anything below their neck. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'close up facial portrait,']", | 306 | "5": "In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, facial features and expressions, occupation, hair and hair accessories (if any), what they are wearing on their upper body (if anything). Do not describe anything below their neck. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'close up facial portrait,'", |
| 307 | "7": "[Pause your roleplay and provide a detailed description of {{char}}'s surroundings in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: location, time of day, weather, lighting, and any other relevant details. Do not include descriptions of characters and non-visual qualities such as names, personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'background,'. Ignore the rest of the story when crafting this description. Do not roleplay as {{user}} when writing this description, and do not attempt to continue the story.]" | 307 | "7": "Ignore previous instructions and provide a detailed description of {{char}}'s surroundings in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: location, time of day, weather, lighting, and any other relevant details. Do not include descriptions of characters and non-visual qualities such as names, personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'background,'. Ignore the rest of the story when crafting this description. Do not reply as {{user}} when writing this description, and do not attempt to continue the story." |
| 308 | }, | 308 | }, |
| 309 | "character_prompts": {} | 309 | "character_prompts": {} |
| 310 | }, | 310 | }, |
| @@ -318,9 +318,9 @@ | |||
| 318 | "objective": { | 318 | "objective": { |
| 319 | "customPrompts": { | 319 | "customPrompts": { |
| 320 | "default": { | 320 | "default": { |
| 321 | "createTask": "Pause your roleplay and generate a list of tasks to complete an objective. Your next response must be formatted as a numbered list of plain text entries. Do not include anything but the numbered list. The list must be prioritized in the order that tasks must be completed.\n\nThe objective that you must make a numbered task list for is: [{{objective}}].\nThe tasks created should take into account the character traits of {{char}}. These tasks may or may not involve {{user}} directly. Be sure to include the objective as the final task.\n\nGiven an example objective of 'Make me a four course dinner', here is an example output:\n1. Determine what the courses will be\n2. Find recipes for each course\n3. Go shopping for supplies with {{user}}\n4. Cook the food\n5. Get {{user}} to set the table\n6. Serve the food\n7. Enjoy eating the meal with {{user}}\n ", | 321 | "createTask": "Ignore previous instructions and generate a list of tasks to complete an objective. Your next response must be formatted as a numbered list of plain text entries. Do not include anything but the numbered list. The list must be prioritized in the order that tasks must be completed.\n\nThe objective that you must make a numbered task list for is: [{{objective}}].\nThe tasks created should take into account the character traits of {{char}}. These tasks may or may not involve {{user}} directly. Be sure to include the objective as the final task.\n\nGiven an example objective of 'Make me a four course dinner', here is an example output:\n1. Determine what the courses will be\n2. Find recipes for each course\n3. Go shopping for supplies with {{user}}\n4. Cook the food\n5. Get {{user}} to set the table\n6. Serve the food\n7. Enjoy eating the meal with {{user}}\n ", |
| 322 | "checkTaskCompleted": "Pause your roleplay. Determine if this task is completed: [{{task}}].\nTo do this, examine the most recent messages. Your response must only contain either true or false, nothing other words.\nExample output:\ntrue\n ", | 322 | "checkTaskCompleted": "Ignore previous instructions. Determine if this task is completed: [{{task}}].\nTo do this, examine the most recent messages. Your response must only contain either true or false, nothing other words.\nExample output:\ntrue\n ", |
| 323 | "currentTask": "Your current task is [{{task}}]. Balance existing roleplay with completing this task." | 323 | "currentTask": "Your current task is [{{task}}]. Balance existing story with completing this task." |
| 324 | } | 324 | } |
| 325 | } | 325 | } |
| 326 | }, | 326 | }, |
| @@ -417,7 +417,6 @@ | |||
| 417 | "preset_settings_novel": "Talker-Chat-Clio", | 417 | "preset_settings_novel": "Talker-Chat-Clio", |
| 418 | "streaming_novel": true, | 418 | "streaming_novel": true, |
| 419 | "preamble": "[ Style: chat, complex, sensory, visceral ]", | 419 | "preamble": "[ Style: chat, complex, sensory, visceral ]", |
| 420 | "cfg_uc": "", | ||
| 421 | "banned_tokens": "", | 420 | "banned_tokens": "", |
| 422 | "order": [ | 421 | "order": [ |
| 423 | 1, | 422 | 1, |
| @@ -1,12 +1,12 @@ | |||
| 1 | { | 1 | { |
| 2 | "name": "sillytavern", | 2 | "name": "sillytavern", |
| 3 | "version": "1.12.5", | 3 | "version": "1.12.6", |
| 4 | "lockfileVersion": 3, | 4 | "lockfileVersion": 3, |
| 5 | "requires": true, | 5 | "requires": true, |
| 6 | "packages": { | 6 | "packages": { |
| 7 | "": { | 7 | "": { |
| 8 | "name": "sillytavern", | 8 | "name": "sillytavern", |
| 9 | "version": "1.12.5", | 9 | "version": "1.12.6", |
| 10 | "hasInstallScript": true, | 10 | "hasInstallScript": true, |
| 11 | "license": "AGPL-3.0", | 11 | "license": "AGPL-3.0", |
| 12 | "dependencies": { | 12 | "dependencies": { |
| @@ -22,7 +22,7 @@ | |||
| 22 | "cookie-session": "^2.1.0", | 22 | "cookie-session": "^2.1.0", |
| 23 | "cors": "^2.8.5", | 23 | "cors": "^2.8.5", |
| 24 | "csrf-csrf": "^2.2.3", | 24 | "csrf-csrf": "^2.2.3", |
| 25 | "express": "^4.20.0", | 25 | "express": "^4.21.0", |
| 26 | "form-data": "^4.0.0", | 26 | "form-data": "^4.0.0", |
| 27 | "google-translate-api-browser": "^3.0.1", | 27 | "google-translate-api-browser": "^3.0.1", |
| 28 | "he": "^1.2.0", | 28 | "he": "^1.2.0", |
| @@ -1568,21 +1568,6 @@ | |||
| 1568 | "node": ">=0.10.0" | 1568 | "node": ">=0.10.0" |
| 1569 | } | 1569 | } |
| 1570 | }, | 1570 | }, |
| 1571 | "node_modules/body-parser/node_modules/qs": { | ||
| 1572 | "version": "6.13.0", | ||
| 1573 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", | ||
| 1574 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", | ||
| 1575 | "license": "BSD-3-Clause", | ||
| 1576 | "dependencies": { | ||
| 1577 | "side-channel": "^1.0.6" | ||
| 1578 | }, | ||
| 1579 | "engines": { | ||
| 1580 | "node": ">=0.6" | ||
| 1581 | }, | ||
| 1582 | "funding": { | ||
| 1583 | "url": "https://github.com/sponsors/ljharb" | ||
| 1584 | } | ||
| 1585 | }, | ||
| 1586 | "node_modules/boolbase": { | 1571 | "node_modules/boolbase": { |
| 1587 | "version": "1.0.0", | 1572 | "version": "1.0.0", |
| 1588 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", | 1573 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", |
| @@ -1728,6 +1713,7 @@ | |||
| 1728 | "version": "2.7.0", | 1713 | "version": "2.7.0", |
| 1729 | "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", | 1714 | "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", |
| 1730 | "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", | 1715 | "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", |
| 1716 | "license": "MIT", | ||
| 1731 | "dependencies": { | 1717 | "dependencies": { |
| 1732 | "follow-redirects": "^1.15.6" | 1718 | "follow-redirects": "^1.15.6" |
| 1733 | } | 1719 | } |
| @@ -2540,9 +2526,9 @@ | |||
| 2540 | "license": "MIT" | 2526 | "license": "MIT" |
| 2541 | }, | 2527 | }, |
| 2542 | "node_modules/encodeurl": { | 2528 | "node_modules/encodeurl": { |
| 2543 | "version": "1.0.2", | 2529 | "version": "2.0.0", |
| 2544 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", | 2530 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", |
| 2545 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", | 2531 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", |
| 2546 | "license": "MIT", | 2532 | "license": "MIT", |
| 2547 | "engines": { | 2533 | "engines": { |
| 2548 | "node": ">= 0.8" | 2534 | "node": ">= 0.8" |
| @@ -2879,9 +2865,9 @@ | |||
| 2879 | "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" | 2865 | "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" |
| 2880 | }, | 2866 | }, |
| 2881 | "node_modules/express": { | 2867 | "node_modules/express": { |
| 2882 | "version": "4.20.0", | 2868 | "version": "4.21.0", |
| 2883 | "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", | 2869 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", |
| 2884 | "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", | 2870 | "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", |
| 2885 | "license": "MIT", | 2871 | "license": "MIT", |
| 2886 | "dependencies": { | 2872 | "dependencies": { |
| 2887 | "accepts": "~1.3.8", | 2873 | "accepts": "~1.3.8", |
| @@ -2896,7 +2882,7 @@ | |||
| 2896 | "encodeurl": "~2.0.0", | 2882 | "encodeurl": "~2.0.0", |
| 2897 | "escape-html": "~1.0.3", | 2883 | "escape-html": "~1.0.3", |
| 2898 | "etag": "~1.8.1", | 2884 | "etag": "~1.8.1", |
| 2899 | "finalhandler": "1.2.0", | 2885 | "finalhandler": "1.3.1", |
| 2900 | "fresh": "0.5.2", | 2886 | "fresh": "0.5.2", |
| 2901 | "http-errors": "2.0.0", | 2887 | "http-errors": "2.0.0", |
| 2902 | "merge-descriptors": "1.0.3", | 2888 | "merge-descriptors": "1.0.3", |
| @@ -2905,11 +2891,11 @@ | |||
| 2905 | "parseurl": "~1.3.3", | 2891 | "parseurl": "~1.3.3", |
| 2906 | "path-to-regexp": "0.1.10", | 2892 | "path-to-regexp": "0.1.10", |
| 2907 | "proxy-addr": "~2.0.7", | 2893 | "proxy-addr": "~2.0.7", |
| 2908 | "qs": "6.11.0", | 2894 | "qs": "6.13.0", |
| 2909 | "range-parser": "~1.2.1", | 2895 | "range-parser": "~1.2.1", |
| 2910 | "safe-buffer": "5.2.1", | 2896 | "safe-buffer": "5.2.1", |
| 2911 | "send": "0.19.0", | 2897 | "send": "0.19.0", |
| 2912 | "serve-static": "1.16.0", | 2898 | "serve-static": "1.16.2", |
| 2913 | "setprototypeof": "1.2.0", | 2899 | "setprototypeof": "1.2.0", |
| 2914 | "statuses": "2.0.1", | 2900 | "statuses": "2.0.1", |
| 2915 | "type-is": "~1.6.18", | 2901 | "type-is": "~1.6.18", |
| @@ -2928,15 +2914,6 @@ | |||
| 2928 | "node": ">= 0.6" | 2914 | "node": ">= 0.6" |
| 2929 | } | 2915 | } |
| 2930 | }, | 2916 | }, |
| 2931 | "node_modules/express/node_modules/encodeurl": { | ||
| 2932 | "version": "2.0.0", | ||
| 2933 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", | ||
| 2934 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", | ||
| 2935 | "license": "MIT", | ||
| 2936 | "engines": { | ||
| 2937 | "node": ">= 0.8" | ||
| 2938 | } | ||
| 2939 | }, | ||
| 2940 | "node_modules/express/node_modules/safe-buffer": { | 2917 | "node_modules/express/node_modules/safe-buffer": { |
| 2941 | "version": "5.2.1", | 2918 | "version": "5.2.1", |
| 2942 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", | 2919 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", |
| @@ -3033,13 +3010,13 @@ | |||
| 3033 | } | 3010 | } |
| 3034 | }, | 3011 | }, |
| 3035 | "node_modules/finalhandler": { | 3012 | "node_modules/finalhandler": { |
| 3036 | "version": "1.2.0", | 3013 | "version": "1.3.1", |
| 3037 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", | 3014 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", |
| 3038 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", | 3015 | "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", |
| 3039 | "license": "MIT", | 3016 | "license": "MIT", |
| 3040 | "dependencies": { | 3017 | "dependencies": { |
| 3041 | "debug": "2.6.9", | 3018 | "debug": "2.6.9", |
| 3042 | "encodeurl": "~1.0.2", | 3019 | "encodeurl": "~2.0.0", |
| 3043 | "escape-html": "~1.0.3", | 3020 | "escape-html": "~1.0.3", |
| 3044 | "on-finished": "2.4.1", | 3021 | "on-finished": "2.4.1", |
| 3045 | "parseurl": "~1.3.3", | 3022 | "parseurl": "~1.3.3", |
| @@ -4080,9 +4057,9 @@ | |||
| 4080 | } | 4057 | } |
| 4081 | }, | 4058 | }, |
| 4082 | "node_modules/load-bmfont": { | 4059 | "node_modules/load-bmfont": { |
| 4083 | "version": "1.4.1", | 4060 | "version": "1.4.2", |
| 4084 | "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.1.tgz", | 4061 | "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.2.tgz", |
| 4085 | "integrity": "sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA==", | 4062 | "integrity": "sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==", |
| 4086 | "license": "MIT", | 4063 | "license": "MIT", |
| 4087 | "dependencies": { | 4064 | "dependencies": { |
| 4088 | "buffer-equal": "0.0.1", | 4065 | "buffer-equal": "0.0.1", |
| @@ -4090,7 +4067,7 @@ | |||
| 4090 | "parse-bmfont-ascii": "^1.0.3", | 4067 | "parse-bmfont-ascii": "^1.0.3", |
| 4091 | "parse-bmfont-binary": "^1.0.5", | 4068 | "parse-bmfont-binary": "^1.0.5", |
| 4092 | "parse-bmfont-xml": "^1.1.4", | 4069 | "parse-bmfont-xml": "^1.1.4", |
| 4093 | "phin": "^2.9.1", | 4070 | "phin": "^3.7.1", |
| 4094 | "xhr": "^2.0.1", | 4071 | "xhr": "^2.0.1", |
| 4095 | "xtend": "^4.0.0" | 4072 | "xtend": "^4.0.0" |
| 4096 | } | 4073 | } |
| @@ -4692,13 +4669,13 @@ | |||
| 4692 | "license": "MIT" | 4669 | "license": "MIT" |
| 4693 | }, | 4670 | }, |
| 4694 | "node_modules/parse-bmfont-xml": { | 4671 | "node_modules/parse-bmfont-xml": { |
| 4695 | "version": "1.1.4", | 4672 | "version": "1.1.6", |
| 4696 | "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz", | 4673 | "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz", |
| 4697 | "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==", | 4674 | "integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==", |
| 4698 | "license": "MIT", | 4675 | "license": "MIT", |
| 4699 | "dependencies": { | 4676 | "dependencies": { |
| 4700 | "xml-parse-from-string": "^1.0.0", | 4677 | "xml-parse-from-string": "^1.0.0", |
| 4701 | "xml2js": "^0.4.5" | 4678 | "xml2js": "^0.5.0" |
| 4702 | } | 4679 | } |
| 4703 | }, | 4680 | }, |
| 4704 | "node_modules/parse-headers": { | 4681 | "node_modules/parse-headers": { |
| @@ -4814,6 +4791,7 @@ | |||
| 4814 | "version": "3.7.1", | 4791 | "version": "3.7.1", |
| 4815 | "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", | 4792 | "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", |
| 4816 | "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", | 4793 | "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", |
| 4794 | "license": "MIT", | ||
| 4817 | "dependencies": { | 4795 | "dependencies": { |
| 4818 | "centra": "^2.7.0" | 4796 | "centra": "^2.7.0" |
| 4819 | }, | 4797 | }, |
| @@ -5032,12 +5010,12 @@ | |||
| 5032 | } | 5010 | } |
| 5033 | }, | 5011 | }, |
| 5034 | "node_modules/qs": { | 5012 | "node_modules/qs": { |
| 5035 | "version": "6.11.0", | 5013 | "version": "6.13.0", |
| 5036 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", | 5014 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", |
| 5037 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", | 5015 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", |
| 5038 | "license": "BSD-3-Clause", | 5016 | "license": "BSD-3-Clause", |
| 5039 | "dependencies": { | 5017 | "dependencies": { |
| 5040 | "side-channel": "^1.0.4" | 5018 | "side-channel": "^1.0.6" |
| 5041 | }, | 5019 | }, |
| 5042 | "engines": { | 5020 | "engines": { |
| 5043 | "node": ">=0.6" | 5021 | "node": ">=0.6" |
| @@ -5344,9 +5322,9 @@ | |||
| 5344 | } | 5322 | } |
| 5345 | }, | 5323 | }, |
| 5346 | "node_modules/sax": { | 5324 | "node_modules/sax": { |
| 5347 | "version": "1.2.4", | 5325 | "version": "1.4.1", |
| 5348 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", | 5326 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", |
| 5349 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", | 5327 | "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", |
| 5350 | "license": "ISC" | 5328 | "license": "ISC" |
| 5351 | }, | 5329 | }, |
| 5352 | "node_modules/send": { | 5330 | "node_modules/send": { |
| @@ -5373,6 +5351,15 @@ | |||
| 5373 | "node": ">= 0.8.0" | 5351 | "node": ">= 0.8.0" |
| 5374 | } | 5352 | } |
| 5375 | }, | 5353 | }, |
| 5354 | "node_modules/send/node_modules/encodeurl": { | ||
| 5355 | "version": "1.0.2", | ||
| 5356 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", | ||
| 5357 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", | ||
| 5358 | "license": "MIT", | ||
| 5359 | "engines": { | ||
| 5360 | "node": ">= 0.8" | ||
| 5361 | } | ||
| 5362 | }, | ||
| 5376 | "node_modules/send/node_modules/ms": { | 5363 | "node_modules/send/node_modules/ms": { |
| 5377 | "version": "2.1.3", | 5364 | "version": "2.1.3", |
| 5378 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | 5365 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", |
| @@ -5380,15 +5367,15 @@ | |||
| 5380 | "license": "MIT" | 5367 | "license": "MIT" |
| 5381 | }, | 5368 | }, |
| 5382 | "node_modules/serve-static": { | 5369 | "node_modules/serve-static": { |
| 5383 | "version": "1.16.0", | 5370 | "version": "1.16.2", |
| 5384 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", | 5371 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", |
| 5385 | "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", | 5372 | "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", |
| 5386 | "license": "MIT", | 5373 | "license": "MIT", |
| 5387 | "dependencies": { | 5374 | "dependencies": { |
| 5388 | "encodeurl": "~1.0.2", | 5375 | "encodeurl": "~2.0.0", |
| 5389 | "escape-html": "~1.0.3", | 5376 | "escape-html": "~1.0.3", |
| 5390 | "parseurl": "~1.3.3", | 5377 | "parseurl": "~1.3.3", |
| 5391 | "send": "0.18.0" | 5378 | "send": "0.19.0" |
| 5392 | }, | 5379 | }, |
| 5393 | "engines": { | 5380 | "engines": { |
| 5394 | "node": ">= 0.8.0" | 5381 | "node": ">= 0.8.0" |
| @@ -12,7 +12,7 @@ | |||
| 12 | "cookie-session": "^2.1.0", | 12 | "cookie-session": "^2.1.0", |
| 13 | "cors": "^2.8.5", | 13 | "cors": "^2.8.5", |
| 14 | "csrf-csrf": "^2.2.3", | 14 | "csrf-csrf": "^2.2.3", |
| 15 | "express": "^4.20.0", | 15 | "express": "^4.21.0", |
| 16 | "form-data": "^4.0.0", | 16 | "form-data": "^4.0.0", |
| 17 | "google-translate-api-browser": "^3.0.1", | 17 | "google-translate-api-browser": "^3.0.1", |
| 18 | "he": "^1.2.0", | 18 | "he": "^1.2.0", |
| @@ -49,23 +49,14 @@ | |||
| 49 | "node": ">= 18" | 49 | "node": ">= 18" |
| 50 | }, | 50 | }, |
| 51 | "overrides": { | 51 | "overrides": { |
| 52 | "parse-bmfont-xml": { | ||
| 53 | "xml2js": "^0.5.0" | ||
| 54 | }, | ||
| 55 | "vectra": { | 52 | "vectra": { |
| 56 | "openai": "^4.17.0" | 53 | "openai": "^4.17.0" |
| 57 | }, | 54 | }, |
| 58 | "load-bmfont": { | ||
| 59 | "phin": "^3.7.1" | ||
| 60 | }, | ||
| 61 | "axios": { | 55 | "axios": { |
| 62 | "follow-redirects": "^1.15.4" | 56 | "follow-redirects": "^1.15.4" |
| 63 | }, | 57 | }, |
| 64 | "node-fetch": { | 58 | "node-fetch": { |
| 65 | "whatwg-url": "^14.0.0" | 59 | "whatwg-url": "^14.0.0" |
| 66 | }, | ||
| 67 | "express": { | ||
| 68 | "send": "^0.19.0" | ||
| 69 | } | 60 | } |
| 70 | }, | 61 | }, |
| 71 | "name": "sillytavern", | 62 | "name": "sillytavern", |
| @@ -75,7 +66,7 @@ | |||
| 75 | "type": "git", | 66 | "type": "git", |
| 76 | "url": "https://github.com/SillyTavern/SillyTavern.git" | 67 | "url": "https://github.com/SillyTavern/SillyTavern.git" |
| 77 | }, | 68 | }, |
| 78 | "version": "1.12.5", | 69 | "version": "1.12.6", |
| 79 | "scripts": { | 70 | "scripts": { |
| 80 | "start": "node server.js", | 71 | "start": "node server.js", |
| 81 | "start:no-csrf": "node server.js --disableCsrf", | 72 | "start:no-csrf": "node server.js --disableCsrf", |
| @@ -103,7 +103,6 @@ | |||
| 103 | touch-action: none; | 103 | touch-action: none; |
| 104 | overflow: hidden; | 104 | overflow: hidden; |
| 105 | position: fixed; | 105 | position: fixed; |
| 106 | |||
| 107 | } | 106 | } |
| 108 | 107 | ||
| 109 | .world_entry_form_control { | 108 | .world_entry_form_control { |
| @@ -112,7 +111,7 @@ | |||
| 112 | 111 | ||
| 113 | .drawer-content { | 112 | .drawer-content { |
| 114 | min-width: unset; | 113 | min-width: unset; |
| 115 | width: 100%; | 114 | width: 100dvw; |
| 116 | max-height: calc(100vh - 45px); | 115 | max-height: calc(100vh - 45px); |
| 117 | max-height: calc(100dvh - 45px); | 116 | max-height: calc(100dvh - 45px); |
| 118 | position: fixed; | 117 | position: fixed; |
| @@ -159,9 +158,9 @@ | |||
| 159 | #sheld, | 158 | #sheld, |
| 160 | #character_popup, | 159 | #character_popup, |
| 161 | .drawer-content { | 160 | .drawer-content { |
| 162 | width: 100% !important; | 161 | width: 100dvw !important; |
| 163 | margin: 0 auto; | 162 | margin: 0 auto; |
| 164 | max-width: 100%; | 163 | max-width: 100dvw; |
| 165 | left: 0 !important; | 164 | left: 0 !important; |
| 166 | resize: none !important; | 165 | resize: none !important; |
| 167 | top: var(--topBarBlockSize); | 166 | top: var(--topBarBlockSize); |
| @@ -233,9 +232,9 @@ | |||
| 233 | /* 100vh are fallback units for browsers that don't support dvh */ | 232 | /* 100vh are fallback units for browsers that don't support dvh */ |
| 234 | height: calc(100vh - 45px); | 233 | height: calc(100vh - 45px); |
| 235 | height: calc(100dvh - 45px); | 234 | height: calc(100dvh - 45px); |
| 236 | min-width: 100% !important; | 235 | min-width: 100dvw !important; |
| 237 | width: 100% !important; | 236 | width: 100dvw !important; |
| 238 | max-width: 100% !important; | 237 | max-width: 100dvw !important; |
| 239 | overflow-y: hidden; | 238 | overflow-y: hidden; |
| 240 | border-left: 1px solid var(--SmartThemeBorderColor); | 239 | border-left: 1px solid var(--SmartThemeBorderColor); |
| 241 | border-right: 1px solid var(--SmartThemeBorderColor); | 240 | border-right: 1px solid var(--SmartThemeBorderColor); |
| @@ -481,10 +480,10 @@ | |||
| 481 | margin: 0 auto; | 480 | margin: 0 auto; |
| 482 | height: calc(100vh - 70px); | 481 | height: calc(100vh - 70px); |
| 483 | height: calc(100dvh - 70px); | 482 | height: calc(100dvh - 70px); |
| 484 | width: calc(100% - 5px); | 483 | width: calc(100dvw - 5px); |
| 485 | max-height: calc(100vh - 70px); | 484 | max-height: calc(100vh - 70px); |
| 486 | max-height: calc(100dvh - 70px); | 485 | max-height: calc(100dvh - 70px); |
| 487 | max-width: calc(100% - 5px); | 486 | max-width: calc(100dvw - 5px); |
| 488 | 487 | ||
| 489 | } | 488 | } |
| 490 | 489 | ||
| @@ -502,4 +501,4 @@ | |||
| 502 | #horde_model { | 501 | #horde_model { |
| 503 | height: unset; | 502 | height: unset; |
| 504 | } | 503 | } |
| 505 | } | ||
| 505 | \ No newline at end of file | \ No newline at end of file | |
| 504 | } | ||
| @@ -47,6 +47,10 @@ dialog { | |||
| 47 | padding: 1px; | 47 | padding: 1px; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | .popup:not(:has(.img_enlarged_container)) .popup-body { | ||
| 51 | max-height: 95dvh; | ||
| 52 | } | ||
| 53 | |||
| 50 | .popup .popup-content { | 54 | .popup .popup-content { |
| 51 | margin-top: 10px; | 55 | margin-top: 10px; |
| 52 | padding: 0 8px; | 56 | padding: 0 8px; |
| @@ -91,15 +91,34 @@ | |||
| 91 | #completion_prompt_manager_popup #completion_prompt_manager_popup_inspect { | 91 | #completion_prompt_manager_popup #completion_prompt_manager_popup_inspect { |
| 92 | display: none; | 92 | display: none; |
| 93 | padding: 0.5em; | 93 | padding: 0.5em; |
| 94 | height: 100%; | ||
| 95 | display: flex; | ||
| 96 | flex-direction: column; | ||
| 94 | } | 97 | } |
| 95 | 98 | ||
| 96 | #completion_prompt_manager_popup .completion_prompt_manager_popup_entry { | 99 | #completion_prompt_manager_popup .completion_prompt_manager_popup_entry { |
| 97 | padding: 1em; | 100 | padding: 0.5em; |
| 98 | margin-top: 2em; | 101 | flex: 1; |
| 102 | } | ||
| 103 | |||
| 104 | #completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form { | ||
| 105 | height: 100%; | ||
| 106 | display: flex; | ||
| 107 | flex-direction: column; | ||
| 108 | } | ||
| 109 | |||
| 110 | #completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form_control:has(#completion_prompt_manager_popup_entry_form_prompt) { | ||
| 111 | flex: 1; | ||
| 112 | display: flex; | ||
| 113 | flex-direction: column; | ||
| 114 | } | ||
| 115 | |||
| 116 | #completion_prompt_manager_popup #completion_prompt_manager_popup_entry_form_prompt { | ||
| 117 | flex: 1; | ||
| 99 | } | 118 | } |
| 100 | 119 | ||
| 101 | #completion_prompt_manager_popup #completion_prompt_manager_popup_inspect .completion_prompt_manager_popup_entry { | 120 | #completion_prompt_manager_popup #completion_prompt_manager_popup_inspect .completion_prompt_manager_popup_entry { |
| 102 | padding: 1em; | 121 | padding: 0.5em; |
| 103 | } | 122 | } |
| 104 | 123 | ||
| 105 | #completion_prompt_manager_popup #completion_prompt_manager_popup_entry_form_inspect_list { | 124 | #completion_prompt_manager_popup #completion_prompt_manager_popup_entry_form_inspect_list { |
| @@ -248,7 +267,7 @@ | |||
| 248 | } | 267 | } |
| 249 | 268 | ||
| 250 | #completion_prompt_manager_footer_append_prompt { | 269 | #completion_prompt_manager_footer_append_prompt { |
| 251 | font-size: 16px; | 270 | font-size: 1em; |
| 252 | } | 271 | } |
| 253 | 272 | ||
| 254 | #prompt-manager-export-format-popup { | 273 | #prompt-manager-export-format-popup { |
| @@ -303,10 +322,6 @@ | |||
| 303 | justify-content: space-between; | 322 | justify-content: space-between; |
| 304 | } | 323 | } |
| 305 | 324 | ||
| 306 | #prompt-manager-export-format-popup span { | ||
| 307 | font-size: 16px; | ||
| 308 | } | ||
| 309 | |||
| 310 | @media screen and (max-width: 412px) { | 325 | @media screen and (max-width: 412px) { |
| 311 | #completion_prompt_manager_popup { | 326 | #completion_prompt_manager_popup { |
| 312 | max-width: 100%; | 327 | max-width: 100%; |
| @@ -316,3 +331,15 @@ | |||
| 316 | margin-left: 0.5em; | 331 | margin-left: 0.5em; |
| 317 | } | 332 | } |
| 318 | } | 333 | } |
| 334 | |||
| 335 | .completion_prompt_manager_popup_entry_form_control:has(#completion_prompt_manager_popup_entry_form_prompt:disabled)>div:first-child::after { | ||
| 336 | content: 'The content of this prompt is pulled from elsewhere and cannot be edited here.'; | ||
| 337 | display: block; | ||
| 338 | width: 100%; | ||
| 339 | font-weight: 600; | ||
| 340 | text-align: center; | ||
| 341 | } | ||
| 342 | |||
| 343 | .completion_prompt_manager_popup_entry_form_control #completion_prompt_manager_popup_entry_form_prompt:disabled { | ||
| 344 | visibility: hidden; | ||
| 345 | } | ||
| @@ -274,3 +274,7 @@ select.keyselect+span.select2-container .select2-selection--multiple { | |||
| 274 | align-self: center; | 274 | align-self: center; |
| 275 | width: 100%; | 275 | width: 100%; |
| 276 | } | 276 | } |
| 277 | |||
| 278 | .world_entry:has(input[name="delay_until_recursion"]:not(:checked)) .world_entry_form_control:has(input[name="delayUntilRecursionLevel"]) { | ||
| 279 | display: none; | ||
| 280 | } | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | <svg xmlns="http://www.w3.org/2000/svg" width="10" height="7"> | ||
| 2 | <polygon points="0,0 10,0 5,7" fill="#888888" /> | ||
| 3 | </svg> | ||
Binary file
| @@ -119,7 +119,7 @@ | |||
| 119 | <option value="gui" data-i18n="Default">Default</option> | 119 | <option value="gui" data-i18n="Default">Default</option> |
| 120 | </select> | 120 | </select> |
| 121 | <div class="flex-container marginLeft5 "> | 121 | <div class="flex-container marginLeft5 "> |
| 122 | <input type="file" hidden data-preset-manager-file="novel" accept=".json, .settings"> | 122 | <input type="file" hidden data-preset-manager-file="novel" accept=".json, .settings, .preset"> |
| 123 | <i data-preset-manager-update="novel" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i> | 123 | <i data-preset-manager-update="novel" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i> |
| 124 | <i data-preset-manager-new="novel" class="menu_button fa-solid fa-file-circle-plus" title="Save preset as" data-i18n="[title]Save preset as"></i> | 124 | <i data-preset-manager-new="novel" class="menu_button fa-solid fa-file-circle-plus" title="Save preset as" data-i18n="[title]Save preset as"></i> |
| 125 | <i data-preset-manager-import="novel" class="menu_button fa-solid fa-file-import" title="Import preset" data-i18n="[title]Import preset"></i> | 125 | <i data-preset-manager-import="novel" class="menu_button fa-solid fa-file-import" title="Import preset" data-i18n="[title]Import preset"></i> |
| @@ -324,6 +324,19 @@ | |||
| 324 | </div> | 324 | </div> |
| 325 | </div> | 325 | </div> |
| 326 | <div class="range-block"> | 326 | <div class="range-block"> |
| 327 | <div class="range-block-title" data-i18n="Min P"> | ||
| 328 | Min P | ||
| 329 | </div> | ||
| 330 | <div class="range-block-range-and-counter"> | ||
| 331 | <div class="range-block-range"> | ||
| 332 | <input type="range" id="min_p_novel" name="volume" min="0" max="1" step="0.001"> | ||
| 333 | </div> | ||
| 334 | <div class="range-block-counter"> | ||
| 335 | <input type="number" min="0" max="1" step="0.001" data-for="min_p_novel" id="min_p_counter_novel"> | ||
| 336 | </div> | ||
| 337 | </div> | ||
| 338 | </div> | ||
| 339 | <div class="range-block"> | ||
| 327 | <div class="range-block-title" data-i18n="TFS"> | 340 | <div class="range-block-title" data-i18n="TFS"> |
| 328 | TFS | 341 | TFS |
| 329 | </div> | 342 | </div> |
| @@ -337,6 +350,136 @@ | |||
| 337 | </div> | 350 | </div> |
| 338 | </div> | 351 | </div> |
| 339 | <div class="range-block"> | 352 | <div class="range-block"> |
| 353 | <div class="range-block-title" data-i18n="Top P"> | ||
| 354 | Top P | ||
| 355 | </div> | ||
| 356 | <div class="range-block-range-and-counter"> | ||
| 357 | <div class="range-block-range"> | ||
| 358 | <input type="range" id="top_p_novel" name="volume" min="0" max="1" step="0.001"> | ||
| 359 | </div> | ||
| 360 | <div class="range-block-counter"> | ||
| 361 | <input type="number" min="0" max="1" step="0.001" data-for="top_p_novel" id="top_p_counter_novel"> | ||
| 362 | </div> | ||
| 363 | </div> | ||
| 364 | </div> | ||
| 365 | <div class="range-block"> | ||
| 366 | <div class="range-block-title" data-i18n="Top A"> | ||
| 367 | Top A | ||
| 368 | </div> | ||
| 369 | <div class="range-block-range-and-counter"> | ||
| 370 | <div class="range-block-range"> | ||
| 371 | <input type="range" id="top_a_novel" name="volume" min="0" max="1" step="0.001"> | ||
| 372 | </div> | ||
| 373 | <div class="range-block-counter"> | ||
| 374 | <input type="number" min="0" max="1" step="0.001" data-for="top_a_novel" id="top_a_counter_novel"> | ||
| 375 | </div> | ||
| 376 | </div> | ||
| 377 | </div> | ||
| 378 | <div class="range-block"> | ||
| 379 | <div class="range-block-title" data-i18n="Top K"> | ||
| 380 | Top K | ||
| 381 | </div> | ||
| 382 | <div class="range-block-range-and-counter"> | ||
| 383 | <div class="range-block-range"> | ||
| 384 | <input type="range" id="top_k_novel" name="volume" min="0" max="300" step="1"> | ||
| 385 | </div> | ||
| 386 | <div class="range-block-counter"> | ||
| 387 | <input type="number" min="0" max="300" step="1" data-for="top_k_novel" id="top_k_counter_novel"> | ||
| 388 | </div> | ||
| 389 | </div> | ||
| 390 | </div> | ||
| 391 | <div class="range-block"> | ||
| 392 | <div class="range-block-title" data-i18n="Mirostat Tau"> | ||
| 393 | Mirostat Tau | ||
| 394 | </div> | ||
| 395 | <div class="range-block-range-and-counter"> | ||
| 396 | <div class="range-block-range"> | ||
| 397 | <input type="range" id="mirostat_tau_novel" name="volume" min="0" max="6" step="0.01"> | ||
| 398 | </div> | ||
| 399 | <div class="range-block-counter"> | ||
| 400 | <input type="number" min="0" max="6" step="0.01" data-for="mirostat_tau_novel" id="mirostat_tau_counter_novel"> | ||
| 401 | </div> | ||
| 402 | </div> | ||
| 403 | </div> | ||
| 404 | <div class="range-block"> | ||
| 405 | <div class="range-block-title" data-i18n="Mirostat LR"> | ||
| 406 | Mirostat LR | ||
| 407 | </div> | ||
| 408 | <div class="range-block-range-and-counter"> | ||
| 409 | <div class="range-block-range"> | ||
| 410 | <input type="range" id="mirostat_lr_novel" name="volume" min="0" max="1" step="0.01"> | ||
| 411 | </div> | ||
| 412 | <div class="range-block-counter"> | ||
| 413 | <input type="number" min="0" max="1" step="0.01" data-for="mirostat_lr_novel" id="mirostat_lr_counter_novel"> | ||
| 414 | </div> | ||
| 415 | </div> | ||
| 416 | </div> | ||
| 417 | <div class="range-block"> | ||
| 418 | <div class="range-block-title" data-i18n="Typical P"> | ||
| 419 | Typical P | ||
| 420 | </div> | ||
| 421 | <div class="range-block-range-and-counter"> | ||
| 422 | <div class="range-block-range"> | ||
| 423 | <input type="range" id="typical_p_novel" name="volume" min="0" max="1" step="0.001"> | ||
| 424 | </div> | ||
| 425 | <div class="range-block-counter"> | ||
| 426 | <input type="number" min="0" max="1" step="0.001" data-for="typical_p_novel" id="typical_p_counter_novel"> | ||
| 427 | </div> | ||
| 428 | </div> | ||
| 429 | </div> | ||
| 430 | <div class="range-block"> | ||
| 431 | <div class="range-block-title" data-i18n="Linear"> | ||
| 432 | Linear | ||
| 433 | </div> | ||
| 434 | <div class="range-block-range-and-counter"> | ||
| 435 | <div class="range-block-range"> | ||
| 436 | <input type="range" id="math1_temp_novel" name="volume" min="0" max="1.5" step="0.01"> | ||
| 437 | </div> | ||
| 438 | <div class="range-block-counter"> | ||
| 439 | <input type="number" min="0" max="1.5" step="0.01" data-for="math1_temp_novel" id="math1_temp_counter_novel"> | ||
| 440 | </div> | ||
| 441 | </div> | ||
| 442 | </div> | ||
| 443 | <div class="range-block"> | ||
| 444 | <div class="range-block-title" data-i18n="Quad"> | ||
| 445 | Quad | ||
| 446 | </div> | ||
| 447 | <div class="range-block-range-and-counter"> | ||
| 448 | <div class="range-block-range"> | ||
| 449 | <input type="range" id="math1_quad_novel" name="volume" min="0" max="0.4" step="0.01"> | ||
| 450 | </div> | ||
| 451 | <div class="range-block-counter"> | ||
| 452 | <input type="number" min="0" max="0.4" step="0.01" data-for="math1_quad_novel" id="math1_quad_counter_novel"> | ||
| 453 | </div> | ||
| 454 | </div> | ||
| 455 | </div> | ||
| 456 | <div class="range-block"> | ||
| 457 | <div class="range-block-title" data-i18n="Conf"> | ||
| 458 | Conf | ||
| 459 | </div> | ||
| 460 | <div class="range-block-range-and-counter"> | ||
| 461 | <div class="range-block-range"> | ||
| 462 | <input type="range" id="math1_quad_entropy_scale_novel" name="volume" min="-0.4" max="0.4" step="0.01"> | ||
| 463 | </div> | ||
| 464 | <div class="range-block-counter"> | ||
| 465 | <input type="number" min="-0.4" max="0.4" step="0.01" data-for="math1_quad_entropy_scale_novel" id="math1_quad_entropy_scale_counter_novel"> | ||
| 466 | </div> | ||
| 467 | </div> | ||
| 468 | </div> | ||
| 469 | <div class="range-block"> | ||
| 470 | <div class="range-block-title" data-i18n="Min Length"> | ||
| 471 | Min Length | ||
| 472 | </div> | ||
| 473 | <div class="range-block-range-and-counter"> | ||
| 474 | <div class="range-block-range"> | ||
| 475 | <input type="range" id="min_length_novel" name="volume" min="1" max="150" step="1"> | ||
| 476 | </div> | ||
| 477 | <div class="range-block-counter"> | ||
| 478 | <input type="number" min="1" max="150" step="1" data-for="min_length_novel" id="min_length_counter_novel"> | ||
| 479 | </div> | ||
| 480 | </div> | ||
| 481 | </div> | ||
| 482 | <div class="range-block"> | ||
| 340 | <div class="range-block-title" data-i18n="Phrase Repetition Penalty"> | 483 | <div class="range-block-title" data-i18n="Phrase Repetition Penalty"> |
| 341 | Phrase Repetition Penalty | 484 | Phrase Repetition Penalty |
| 342 | </div> | 485 | </div> |
| @@ -349,6 +492,46 @@ | |||
| 349 | <option value="very_aggressive" data-i18n="Very aggressive">Very aggressive</option> | 492 | <option value="very_aggressive" data-i18n="Very aggressive">Very aggressive</option> |
| 350 | </select> | 493 | </select> |
| 351 | </div> | 494 | </div> |
| 495 | <div class="range-block"> | ||
| 496 | <div class="range-block-title openai_restorable"> | ||
| 497 | <span data-i18n="Preamble">Preamble</span> | ||
| 498 | <div id="nai_preamble_restore" title="Restore default prompt" data-i18n="[title]Restore default prompt" class="right_menu_button"> | ||
| 499 | <div class="fa-solid fa-clock-rotate-left "></div> | ||
| 500 | </div> | ||
| 501 | </div> | ||
| 502 | <div class="toggle-description justifyLeft" data-i18n="Use style tags to modify the writing style of the output."> | ||
| 503 | Use style tags to modify the writing style of the output. | ||
| 504 | </div> | ||
| 505 | <div class="wide100p"> | ||
| 506 | <textarea id="nai_preamble_textarea" class="text_pole textarea_compact" name="nai_preamble" rows="2" placeholder=""></textarea> | ||
| 507 | </div> | ||
| 508 | </div> | ||
| 509 | <div class="range-block"> | ||
| 510 | <div class="range-block-title justifyLeft"> | ||
| 511 | <span data-i18n="Banned Tokens">Banned Tokens</span> | ||
| 512 | </div> | ||
| 513 | <div class="toggle-description justifyLeft" data-i18n="Sequences you don't want to appear in the output. One per line."> | ||
| 514 | Sequences you don't want to appear in the output. One per line. Text or [token ids]. | ||
| 515 | </div> | ||
| 516 | <div class="wide100p"> | ||
| 517 | <textarea id="nai_banned_tokens" class="text_pole textarea_compact" name="nai_banned_tokens" rows="3" placeholder="Example: some text [42, 69, 1337]"></textarea> | ||
| 518 | </div> | ||
| 519 | </div> | ||
| 520 | <div class="range-block"> | ||
| 521 | <div id="logit_bias_novel" class="range-block-title title_restorable"> | ||
| 522 | <span data-i18n="Logit Bias">Logit Bias</span> | ||
| 523 | <div id="novelai_logit_bias_new_entry" class="menu_button menu_button_icon"> | ||
| 524 | <i class="fa-xs fa-solid fa-plus"></i> | ||
| 525 | <small data-i18n="Add">Add</small> | ||
| 526 | </div> | ||
| 527 | </div> | ||
| 528 | <div class="toggle-description justifyLeft" data-i18n="Helps to ban or reenforce the usage of certain words"> | ||
| 529 | Helps to ban or reinforce the usage of certain tokens. | ||
| 530 | </div> | ||
| 531 | <div class="flex-container flexFlowColumn wide100p"> | ||
| 532 | <div class="logit_bias_list"></div> | ||
| 533 | </div> | ||
| 534 | </div> | ||
| 352 | </div> | 535 | </div> |
| 353 | <div id="range_block_openai"> | 536 | <div id="range_block_openai"> |
| 354 | <div class="range-block"> | 537 | <div class="range-block"> |
| @@ -907,163 +1090,6 @@ | |||
| 907 | </div> | 1090 | </div> |
| 908 | </div><!-- end of kobold settings--> | 1091 | </div><!-- end of kobold settings--> |
| 909 | <div id="novel_api-settings"> | 1092 | <div id="novel_api-settings"> |
| 910 | <div class="range-block"> | ||
| 911 | <div class="range-block-title openai_restorable"> | ||
| 912 | <span data-i18n="Preamble">Preamble</span> | ||
| 913 | <div id="nai_preamble_restore" title="Restore default prompt" data-i18n="[title]Restore default prompt" class="right_menu_button"> | ||
| 914 | <div class="fa-solid fa-clock-rotate-left "></div> | ||
| 915 | </div> | ||
| 916 | </div> | ||
| 917 | <div class="toggle-description justifyLeft" data-i18n="Use style tags to modify the writing style of the output."> | ||
| 918 | Use style tags to modify the writing style of the output. | ||
| 919 | </div> | ||
| 920 | <div class="wide100p"> | ||
| 921 | <textarea id="nai_preamble_textarea" class="text_pole textarea_compact" name="nai_preamble" rows="2" placeholder=""></textarea> | ||
| 922 | </div> | ||
| 923 | </div> | ||
| 924 | <div class="range-block"> | ||
| 925 | <div class="range-block-title justifyLeft"> | ||
| 926 | <span data-i18n="Banned Tokens">Banned Tokens</span> | ||
| 927 | </div> | ||
| 928 | <div class="toggle-description justifyLeft" data-i18n="Sequences you don't want to appear in the output. One per line."> | ||
| 929 | Sequences you don't want to appear in the output. One per line. Text or [token ids]. | ||
| 930 | </div> | ||
| 931 | <div class="wide100p"> | ||
| 932 | <textarea id="nai_banned_tokens" class="text_pole textarea_compact" name="nai_banned_tokens" rows="3" placeholder="Example: some text [42, 69, 1337]"></textarea> | ||
| 933 | </div> | ||
| 934 | </div> | ||
| 935 | <div class="range-block"> | ||
| 936 | <div id="logit_bias_novel" class="range-block-title title_restorable"> | ||
| 937 | <span data-i18n="Logit Bias">Logit Bias</span> | ||
| 938 | <div id="novelai_logit_bias_new_entry" class="menu_button menu_button_icon"> | ||
| 939 | <i class="fa-xs fa-solid fa-plus"></i> | ||
| 940 | <small data-i18n="Add">Add</small> | ||
| 941 | </div> | ||
| 942 | </div> | ||
| 943 | <div class="toggle-description justifyLeft" data-i18n="Helps to ban or reenforce the usage of certain words"> | ||
| 944 | Helps to ban or reinforce the usage of certain tokens. | ||
| 945 | </div> | ||
| 946 | <div class="flex-container flexFlowColumn wide100p"> | ||
| 947 | <div class="logit_bias_list"></div> | ||
| 948 | </div> | ||
| 949 | </div> | ||
| 950 | <div class="range-block"> | ||
| 951 | <hr> | ||
| 952 | <div class="range-block-title justifyLeft" data-i18n="CFG Scale"> | ||
| 953 | CFG Scale | ||
| 954 | </div> | ||
| 955 | <div class="range-block-range-and-counter"> | ||
| 956 | <div class="range-block-range"> | ||
| 957 | <input type="range" id="cfg_scale_novel" name="volume" min="1" max="3" step="0.05"> | ||
| 958 | </div> | ||
| 959 | <div class="range-block-counter"> | ||
| 960 | <input type="number" min="1" max="3" step="0.05" data-for="cfg_scale_novel" id="cfg_scale_counter_novel"> | ||
| 961 | </div> | ||
| 962 | </div> | ||
| 963 | </div> | ||
| 964 | <div class="range-block"> | ||
| 965 | <div class="range-block-title justifyLeft"> | ||
| 966 | <span data-i18n="Negative Prompt">Negative Prompt</span> | ||
| 967 | </div> | ||
| 968 | <div class="wide100p"> | ||
| 969 | <textarea id="nai_cfg_uc" class="text_pole textarea_compact" name="cfg_uc" rows="2" data-i18n="[placeholder]Add text here that would make the AI generate things you don't want in your outputs." placeholder="Add text here that would make the AI generate things you don't want in your outputs."></textarea> | ||
| 970 | </div> | ||
| 971 | <small class="margin-bot-10px" data-i18n="Used if CFG Scale is unset globally, per chat or character"> | ||
| 972 | Used if CFG Scale is unset globally, per chat or character | ||
| 973 | </small> | ||
| 974 | <hr> | ||
| 975 | </div> | ||
| 976 | <div class="range-block"> | ||
| 977 | <div class="range-block-title" data-i18n="Top P"> | ||
| 978 | Top P | ||
| 979 | </div> | ||
| 980 | <div class="range-block-range-and-counter"> | ||
| 981 | <div class="range-block-range"> | ||
| 982 | <input type="range" id="top_p_novel" name="volume" min="0" max="1" step="0.001"> | ||
| 983 | </div> | ||
| 984 | <div class="range-block-counter"> | ||
| 985 | <input type="number" min="0" max="1" step="0.001" data-for="top_p_novel" id="top_p_counter_novel"> | ||
| 986 | </div> | ||
| 987 | </div> | ||
| 988 | </div> | ||
| 989 | <div class="range-block"> | ||
| 990 | <div class="range-block-title" data-i18n="Top A"> | ||
| 991 | Top A | ||
| 992 | </div> | ||
| 993 | <div class="range-block-range-and-counter"> | ||
| 994 | <div class="range-block-range"> | ||
| 995 | <input type="range" id="top_a_novel" name="volume" min="0" max="1" step="0.001"> | ||
| 996 | </div> | ||
| 997 | <div class="range-block-counter"> | ||
| 998 | <input type="number" min="0" max="1" step="0.001" data-for="top_a_novel" id="top_a_counter_novel"> | ||
| 999 | </div> | ||
| 1000 | </div> | ||
| 1001 | </div> | ||
| 1002 | <div class="range-block"> | ||
| 1003 | <div class="range-block-title" data-i18n="Top K"> | ||
| 1004 | Top K | ||
| 1005 | </div> | ||
| 1006 | <div class="range-block-range-and-counter"> | ||
| 1007 | <div class="range-block-range"> | ||
| 1008 | <input type="range" id="top_k_novel" name="volume" min="0" max="300" step="1"> | ||
| 1009 | </div> | ||
| 1010 | <div class="range-block-counter"> | ||
| 1011 | <input type="number" min="0" max="300" step="1" data-for="top_k_novel" id="top_k_counter_novel"> | ||
| 1012 | </div> | ||
| 1013 | </div> | ||
| 1014 | </div> | ||
| 1015 | <div class="range-block"> | ||
| 1016 | <div class="range-block-title" data-i18n="Mirostat Tau"> | ||
| 1017 | Mirostat Tau | ||
| 1018 | </div> | ||
| 1019 | <div class="range-block-range-and-counter"> | ||
| 1020 | <div class="range-block-range"> | ||
| 1021 | <input type="range" id="mirostat_tau_novel" name="volume" min="0" max="6" step="0.01"> | ||
| 1022 | </div> | ||
| 1023 | <div class="range-block-counter"> | ||
| 1024 | <input type="number" min="0" max="6" step="0.01" data-for="mirostat_tau_novel" id="mirostat_tau_counter_novel"> | ||
| 1025 | </div> | ||
| 1026 | </div> | ||
| 1027 | </div> | ||
| 1028 | <div class="range-block"> | ||
| 1029 | <div class="range-block-title" data-i18n="Mirostat LR"> | ||
| 1030 | Mirostat LR | ||
| 1031 | </div> | ||
| 1032 | <div class="range-block-range-and-counter"> | ||
| 1033 | <div class="range-block-range"> | ||
| 1034 | <input type="range" id="mirostat_lr_novel" name="volume" min="0" max="1" step="0.01"> | ||
| 1035 | </div> | ||
| 1036 | <div class="range-block-counter"> | ||
| 1037 | <input type="number" min="0" max="1" step="0.01" data-for="mirostat_lr_novel" id="mirostat_lr_counter_novel"> | ||
| 1038 | </div> | ||
| 1039 | </div> | ||
| 1040 | </div> | ||
| 1041 | <div class="range-block"> | ||
| 1042 | <div class="range-block-title" data-i18n="Typical P"> | ||
| 1043 | Typical P | ||
| 1044 | </div> | ||
| 1045 | <div class="range-block-range-and-counter"> | ||
| 1046 | <div class="range-block-range"> | ||
| 1047 | <input type="range" id="typical_p_novel" name="volume" min="0" max="1" step="0.001"> | ||
| 1048 | </div> | ||
| 1049 | <div class="range-block-counter"> | ||
| 1050 | <input type="number" min="0" max="1" step="0.001" data-for="typical_p_novel" id="typical_p_counter_novel"> | ||
| 1051 | </div> | ||
| 1052 | </div> | ||
| 1053 | </div> | ||
| 1054 | <div class="range-block"> | ||
| 1055 | <div class="range-block-title" data-i18n="Min Length"> | ||
| 1056 | Min Length | ||
| 1057 | </div> | ||
| 1058 | <div class="range-block-range-and-counter"> | ||
| 1059 | <div class="range-block-range"> | ||
| 1060 | <input type="range" id="min_length_novel" name="volume" min="1" max="150" step="1"> | ||
| 1061 | </div> | ||
| 1062 | <div class="range-block-counter"> | ||
| 1063 | <input type="number" min="1" max="150" step="1" data-for="min_length_novel" id="min_length_counter_novel"> | ||
| 1064 | </div> | ||
| 1065 | </div> | ||
| 1066 | </div> | ||
| 1067 | <div class="range-block flexFlowColumn"> | 1093 | <div class="range-block flexFlowColumn"> |
| 1068 | <div class="range-block-title"> | 1094 | <div class="range-block-title"> |
| 1069 | <span data-i18n="Samplers Order">Samplers Order</span> | 1095 | <span data-i18n="Samplers Order">Samplers Order</span> |
| @@ -1102,17 +1128,22 @@ | |||
| 1102 | <small>5</small> | 1128 | <small>5</small> |
| 1103 | <div class="toggle_button right_menu_button"></div> | 1129 | <div class="toggle_button right_menu_button"></div> |
| 1104 | </div> | 1130 | </div> |
| 1105 | <div data-id="6"> | 1131 | <!-- 6 and 7 were removed samplers. --> |
| 1106 | <span data-i18n="CFG">CFG</span> | ||
| 1107 | <small>6</small> | ||
| 1108 | <div class="toggle_button right_menu_button"></div> | ||
| 1109 | </div> | ||
| 1110 | <!-- Yes, there is no 7. It was a removed Top G sampling. RIP. --> | ||
| 1111 | <div data-id="8"> | 1132 | <div data-id="8"> |
| 1112 | <span data-i18n="Mirostat">Mirostat</span> | 1133 | <span data-i18n="Mirostat">Mirostat</span> |
| 1113 | <small>8</small> | 1134 | <small>8</small> |
| 1114 | <div class="toggle_button right_menu_button"></div> | 1135 | <div class="toggle_button right_menu_button"></div> |
| 1115 | </div> | 1136 | </div> |
| 1137 | <div data-id="9"> | ||
| 1138 | <span data-i18n="Unified Sampling">Unified Sampling</span> | ||
| 1139 | <small>9</small> | ||
| 1140 | <div class="toggle_button right_menu_button"></div> | ||
| 1141 | </div> | ||
| 1142 | <div data-id="10"> | ||
| 1143 | <span data-i18n="Min P">Min P</span> | ||
| 1144 | <small>10</small> | ||
| 1145 | <div class="toggle_button right_menu_button"></div> | ||
| 1146 | </div> | ||
| 1116 | </div> | 1147 | </div> |
| 1117 | </div> | 1148 | </div> |
| 1118 | </div><!-- end of novel settings--> | 1149 | </div><!-- end of novel settings--> |
| @@ -1279,7 +1310,7 @@ | |||
| 1279 | </div> | 1310 | </div> |
| 1280 | </div> | 1311 | </div> |
| 1281 | 1312 | ||
| 1282 | <div data-tg-type="koboldcpp" id="xtc_block" class="wide100p"> | 1313 | <div data-tg-type="koboldcpp, aphrodite" id="xtc_block" class="wide100p"> |
| 1283 | <h4 class="wide100p textAlignCenter"> | 1314 | <h4 class="wide100p textAlignCenter"> |
| 1284 | <label data-i18n="Exclude Top Choices (XTC)">Exclude Top Choices (XTC)</label> | 1315 | <label data-i18n="Exclude Top Choices (XTC)">Exclude Top Choices (XTC)</label> |
| 1285 | <a href="https://github.com/oobabooga/text-generation-webui/pull/6335" target="_blank"> | 1316 | <a href="https://github.com/oobabooga/text-generation-webui/pull/6335" target="_blank"> |
| @@ -1339,7 +1370,7 @@ | |||
| 1339 | </div> | 1370 | </div> |
| 1340 | </div> | 1371 | </div> |
| 1341 | </div> | 1372 | </div> |
| 1342 | <div data-tg-type="ooba, mancer, koboldcpp, tabby, llamacpp" id="dynatemp_block_ooba" class="wide100p"> | 1373 | <div data-tg-type="ooba, mancer, koboldcpp, tabby, llamacpp, aphrodite" id="dynatemp_block_ooba" class="wide100p"> |
| 1343 | <h4 class="wide100p textAlignCenter"> | 1374 | <h4 class="wide100p textAlignCenter"> |
| 1344 | <div class="flex-container alignitemscenter justifyCenter"> | 1375 | <div class="flex-container alignitemscenter justifyCenter"> |
| 1345 | <div class="checkbox_label" for="dynatemp_textgenerationwebui"> | 1376 | <div class="checkbox_label" for="dynatemp_textgenerationwebui"> |
| @@ -2038,6 +2069,7 @@ | |||
| 2038 | <select id="model_novel_select"> | 2069 | <select id="model_novel_select"> |
| 2039 | <option value="clio-v1">Clio</option> | 2070 | <option value="clio-v1">Clio</option> |
| 2040 | <option value="kayra-v1">Kayra</option> | 2071 | <option value="kayra-v1">Kayra</option> |
| 2072 | <option value="llama-3-erato-v1">Erato</option> | ||
| 2041 | </select> | 2073 | </select> |
| 2042 | <div class="flex-container"> | 2074 | <div class="flex-container"> |
| 2043 | <div id="api_button_novel" class="api_button menu_button menu_button_icon" type="submit" data-i18n="Connect">Connect</div> | 2075 | <div id="api_button_novel" class="api_button menu_button menu_button_icon" type="submit" data-i18n="Connect">Connect</div> |
| @@ -2850,10 +2882,13 @@ | |||
| 2850 | <option value="gemini-1.5-pro-exp-0827">Gemini 1.5 Pro Experiment 2024-08-27</option> | 2882 | <option value="gemini-1.5-pro-exp-0827">Gemini 1.5 Pro Experiment 2024-08-27</option> |
| 2851 | <option value="gemini-1.5-pro-latest">Gemini 1.5 Pro [latest]</option> | 2883 | <option value="gemini-1.5-pro-latest">Gemini 1.5 Pro [latest]</option> |
| 2852 | <option value="gemini-1.5-pro-001">Gemini 1.5 Pro [001]</option> | 2884 | <option value="gemini-1.5-pro-001">Gemini 1.5 Pro [001]</option> |
| 2885 | <option value="gemini-1.5-pro-002">Gemini 1.5 Pro [002]</option> | ||
| 2853 | <option value="gemini-1.5-flash-exp-0827">Gemini 1.5 Flash Experiment 2024-08-27</option> | 2886 | <option value="gemini-1.5-flash-exp-0827">Gemini 1.5 Flash Experiment 2024-08-27</option> |
| 2854 | <option value="gemini-1.5-flash-8b-exp-0827">Gemini 1.5 Flash 8B Experiment 2024-08-27</option> | 2887 | <option value="gemini-1.5-flash-8b-exp-0827">Gemini 1.5 Flash 8B Experiment 2024-08-27</option> |
| 2888 | <option value="gemini-1.5-flash-8b-exp-0924">Gemini 1.5 Flash 8B Experiment 2024-09-24</option> | ||
| 2855 | <option value="gemini-1.5-flash-latest">Gemini 1.5 Flash [latest]</option> | 2889 | <option value="gemini-1.5-flash-latest">Gemini 1.5 Flash [latest]</option> |
| 2856 | <option value="gemini-1.5-flash-001">Gemini 1.5 Flash [001]</option> | 2890 | <option value="gemini-1.5-flash-001">Gemini 1.5 Flash [001]</option> |
| 2891 | <option value="gemini-1.5-flash-002">Gemini 1.5 Flash [002]</option> | ||
| 2857 | <option value="gemini-1.0-pro-latest">Gemini 1.0 Pro [latest]</option> | 2892 | <option value="gemini-1.0-pro-latest">Gemini 1.0 Pro [latest]</option> |
| 2858 | <option value="gemini-1.0-pro-001">Gemini 1.0 Pro (Tuning) [001]</option> | 2893 | <option value="gemini-1.0-pro-001">Gemini 1.0 Pro (Tuning) [001]</option> |
| 2859 | <option value="gemini-1.0-pro-vision-latest">Gemini 1.0 Pro Vision [latest]</option> | 2894 | <option value="gemini-1.0-pro-vision-latest">Gemini 1.0 Pro Vision [latest]</option> |
| @@ -2884,6 +2919,7 @@ | |||
| 2884 | <option value="mistral-large-latest">mistral-large-latest</option> | 2919 | <option value="mistral-large-latest">mistral-large-latest</option> |
| 2885 | <option value="codestral-latest">codestral-latest</option> | 2920 | <option value="codestral-latest">codestral-latest</option> |
| 2886 | <option value="codestral-mamba-latest">codestral-mamba-latest</option> | 2921 | <option value="codestral-mamba-latest">codestral-mamba-latest</option> |
| 2922 | <option value="pixtral-latest">pixtral-latest</option> | ||
| 2887 | </optgroup> | 2923 | </optgroup> |
| 2888 | <optgroup label="Sub-versions"> | 2924 | <optgroup label="Sub-versions"> |
| 2889 | <option value="open-mistral-nemo-2407">open-mistral-nemo-2407</option> | 2925 | <option value="open-mistral-nemo-2407">open-mistral-nemo-2407</option> |
| @@ -2891,11 +2927,13 @@ | |||
| 2891 | <option value="mistral-tiny-2312">mistral-tiny-2312</option> | 2927 | <option value="mistral-tiny-2312">mistral-tiny-2312</option> |
| 2892 | <option value="mistral-small-2312">mistral-small-2312</option> | 2928 | <option value="mistral-small-2312">mistral-small-2312</option> |
| 2893 | <option value="mistral-small-2402">mistral-small-2402</option> | 2929 | <option value="mistral-small-2402">mistral-small-2402</option> |
| 2930 | <option value="mistral-small-2409">mistral-small-2409</option> | ||
| 2894 | <option value="mistral-medium-2312">mistral-medium-2312</option> | 2931 | <option value="mistral-medium-2312">mistral-medium-2312</option> |
| 2895 | <option value="mistral-large-2402">mistral-large-2402</option> | 2932 | <option value="mistral-large-2402">mistral-large-2402</option> |
| 2896 | <option value="mistral-large-2407">mistral-large-2407</option> | 2933 | <option value="mistral-large-2407">mistral-large-2407</option> |
| 2897 | <option value="codestral-2405">codestral-2405</option> | 2934 | <option value="codestral-2405">codestral-2405</option> |
| 2898 | <option value="codestral-mamba-2407">codestral-mamba-2407</option> | 2935 | <option value="codestral-mamba-2407">codestral-mamba-2407</option> |
| 2936 | <option value="pixtral-12b-2409">pixtral-12b-2409</option> | ||
| 2899 | </optgroup> | 2937 | </optgroup> |
| 2900 | </select> | 2938 | </select> |
| 2901 | </div> | 2939 | </div> |
| @@ -3085,9 +3123,22 @@ | |||
| 3085 | <div class="drawer-icon fa-solid fa-font fa-fw closedIcon" title="AI Response Formatting" data-i18n="[title]AI Response Formatting"></div> | 3123 | <div class="drawer-icon fa-solid fa-font fa-fw closedIcon" title="AI Response Formatting" data-i18n="[title]AI Response Formatting"></div> |
| 3086 | </div> | 3124 | </div> |
| 3087 | <div id="AdvancedFormatting" class="drawer-content"> | 3125 | <div id="AdvancedFormatting" class="drawer-content"> |
| 3088 | <h3 class="margin0" data-i18n="Advanced Formatting"> | 3126 | <div class="flex-container alignItemsBaseline"> |
| 3089 | Advanced Formatting | 3127 | <h3 class="margin0 flex1" data-i18n="Advanced Formatting"> |
| 3090 | </h3> | 3128 | Advanced Formatting |
| 3129 | </h3> | ||
| 3130 | <div class="flex-container"> | ||
| 3131 | <input id="af_master_import_file" type="file" hidden accept=".json" class="displayNone"> | ||
| 3132 | <div id="af_master_import" class="menu_button menu_button_icon" title="Import Advanced Formatting settings You can also provide legacy files for Instruct and Context templates." data-i18n="[title]Import Advanced Formatting settings"> | ||
| 3133 | <i class="fa-solid fa-file-import"></i> | ||
| 3134 | <span data-i18n="Master Import">Master Import</span> | ||
| 3135 | </div> | ||
| 3136 | <div id="af_master_export" class="menu_button menu_button_icon" title="Export Advanced Formatting settings" data-i18n="[title]Export Advanced Formatting settings"> | ||
| 3137 | <i class="fa-solid fa-file-export"></i> | ||
| 3138 | <span data-i18n="Master Export">Master Export</span> | ||
| 3139 | </div> | ||
| 3140 | </div> | ||
| 3141 | </div> | ||
| 3091 | <div class="flex-container spaceEvenly"> | 3142 | <div class="flex-container spaceEvenly"> |
| 3092 | <div id="ContextSettings" class="flex-container flexNoGap flexFlowColumn flex1"> | 3143 | <div id="ContextSettings" class="flex-container flexNoGap flexFlowColumn flex1"> |
| 3093 | <div> | 3144 | <div> |
| @@ -3099,18 +3150,17 @@ | |||
| 3099 | </a> | 3150 | </a> |
| 3100 | </div> | 3151 | </div> |
| 3101 | </h4> | 3152 | </h4> |
| 3102 | <div class="flex-container justifyCenter"> | ||
| 3103 | <input type="file" hidden data-preset-manager-file="context" accept=".json, .settings"> | ||
| 3104 | <i id="context_set_default" class="menu_button fa-solid fa-heart" title="Auto-select this template for Instruct Mode." data-i18n="[title]Auto-select this template for Instruct Mode"></i> | ||
| 3105 | <i data-preset-manager-update="context" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i> | ||
| 3106 | <i data-preset-manager-new="context" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i> | ||
| 3107 | <i data-preset-manager-import="context" class="menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i> | ||
| 3108 | <i data-preset-manager-export="context" class="menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i> | ||
| 3109 | <i data-preset-manager-restore="context" class="menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i> | ||
| 3110 | <i id="context_delete_preset" data-preset-manager-delete="context" class="menu_button fa-solid fa-trash-can" title="Delete the template" data-i18n="[title]Delete the template"></i> | ||
| 3111 | </div> | ||
| 3112 | <div class="flex-container" title="Select your current Context Template" data-i18n="[title]Select your current Context Template"> | 3153 | <div class="flex-container" title="Select your current Context Template" data-i18n="[title]Select your current Context Template"> |
| 3113 | <select id="context_presets" data-preset-manager-for="context" class="flex1 text_pole"></select> | 3154 | <select id="context_presets" data-preset-manager-for="context" class="flex1 text_pole"></select> |
| 3155 | <div class="flex-container justifyCenter"> | ||
| 3156 | <input type="file" hidden data-preset-manager-file="context" accept=".json, .settings"> | ||
| 3157 | <i data-preset-manager-update="context" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i> | ||
| 3158 | <i data-preset-manager-new="context" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i> | ||
| 3159 | <i data-preset-manager-import="context" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i> | ||
| 3160 | <i data-preset-manager-export="context" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i> | ||
| 3161 | <i data-preset-manager-restore="context" class="menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i> | ||
| 3162 | <i id="context_delete_preset" data-preset-manager-delete="context" class="menu_button fa-solid fa-trash-can" title="Delete the template" data-i18n="[title]Delete the template"></i> | ||
| 3163 | </div> | ||
| 3114 | </div> | 3164 | </div> |
| 3115 | <div> | 3165 | <div> |
| 3116 | <label for="context_story_string" class="flex-container"> | 3166 | <label for="context_story_string" class="flex-container"> |
| @@ -3141,9 +3191,6 @@ | |||
| 3141 | <span data-i18n="Context Formatting"> | 3191 | <span data-i18n="Context Formatting"> |
| 3142 | Context Formatting | 3192 | Context Formatting |
| 3143 | </span> | 3193 | </span> |
| 3144 | <small data-i18n="(Saves to Template)"> | ||
| 3145 | (Saves to Template) | ||
| 3146 | </small> | ||
| 3147 | </h4> | 3194 | </h4> |
| 3148 | 3195 | ||
| 3149 | <label class="checkbox_label" for="always-force-name2-checkbox"> | 3196 | <label class="checkbox_label" for="always-force-name2-checkbox"> |
| @@ -3174,11 +3221,6 @@ | |||
| 3174 | Trim Incomplete Sentences | 3221 | Trim Incomplete Sentences |
| 3175 | </small> | 3222 | </small> |
| 3176 | </label> | 3223 | </label> |
| 3177 | <!-- Add margin since this is a child of above --> | ||
| 3178 | <label class="checkbox_label indent20p" for="include_newline_checkbox"> | ||
| 3179 | <input id="include_newline_checkbox" type="checkbox" /> | ||
| 3180 | <small data-i18n="Include Newline">Include Newline</small> | ||
| 3181 | </label> | ||
| 3182 | <label class="checkbox_label" title="Add Chat Start and Example Separator to a list of stopping strings." data-i18n="[title]Add Chat Start and Example Separator to a list of stopping strings."> | 3224 | <label class="checkbox_label" title="Add Chat Start and Example Separator to a list of stopping strings." data-i18n="[title]Add Chat Start and Example Separator to a list of stopping strings."> |
| 3183 | <input id="context_use_stop_strings" type="checkbox" /> | 3225 | <input id="context_use_stop_strings" type="checkbox" /> |
| 3184 | <small data-i18n="Separators as Stop Strings">Separators as Stop Strings</small> | 3226 | <small data-i18n="Separators as Stop Strings">Separators as Stop Strings</small> |
| @@ -3194,31 +3236,6 @@ | |||
| 3194 | <small data-i18n="Allow Post-History Instructions">Allow Post-History Instructions</small> | 3236 | <small data-i18n="Allow Post-History Instructions">Allow Post-History Instructions</small> |
| 3195 | </label> | 3237 | </label> |
| 3196 | </div> | 3238 | </div> |
| 3197 | <div> | ||
| 3198 | <h4 class="range-block-title justifyLeft standoutHeader"> | ||
| 3199 | <span data-i18n="Custom Stopping Strings"> | ||
| 3200 | Custom Stopping Strings | ||
| 3201 | </span> | ||
| 3202 | <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#custom-stopping-strings" class="notes-link" target="_blank"> | ||
| 3203 | <span class="fa-solid fa-circle-question note-link-span"></span> | ||
| 3204 | </a> | ||
| 3205 | </h4> | ||
| 3206 | <div> | ||
| 3207 | <small> | ||
| 3208 | <span data-i18n="JSON serialized array of strings">JSON serialized array of strings</span> | ||
| 3209 | <i class="fa-solid fa-question-circle opacity50p" title="e.g: ["Ford", "BMW", "Fiat"]"></i> | ||
| 3210 | </small> | ||
| 3211 | </div> | ||
| 3212 | <div> | ||
| 3213 | <textarea id="custom_stopping_strings" class="text_pole textarea_compact monospace autoSetHeight"></textarea> | ||
| 3214 | </div> | ||
| 3215 | <label class="checkbox_label" for="custom_stopping_strings_macro"> | ||
| 3216 | <input id="custom_stopping_strings_macro" type="checkbox" checked> | ||
| 3217 | <small data-i18n="Replace Macro in Custom Stopping Strings"> | ||
| 3218 | Replace Macro in Custom Stopping Strings | ||
| 3219 | </small> | ||
| 3220 | </label> | ||
| 3221 | </div> | ||
| 3222 | </div> | 3239 | </div> |
| 3223 | </div> | 3240 | </div> |
| 3224 | <div id="InstructSettingsColumn" class="flex-container flexNoGap flexFlowColumn flex1"> | 3241 | <div id="InstructSettingsColumn" class="flex-container flexNoGap flexFlowColumn flex1"> |
| @@ -3231,29 +3248,28 @@ | |||
| 3231 | </a> | 3248 | </a> |
| 3232 | </div> | 3249 | </div> |
| 3233 | <div class="flex-container"> | 3250 | <div class="flex-container"> |
| 3234 | <label for="instruct_enabled" class="checkbox_label flex1" title="Enable Instruct Mode" data-i18n="[title]instruct_enabled"> | ||
| 3235 | <input id="instruct_enabled" type="checkbox" style="display:none;" /> | ||
| 3236 | <small><i class="fa-solid fa-power-off menu_button margin0"></i></small> | ||
| 3237 | </label> | ||
| 3238 | <label for="instruct_bind_to_context" class="checkbox_label flex1" title="Bind to Context
If enabled, Context templates will be automatically selected based on selected Instruct template name or by preference." data-i18n="[title]instruct_bind_to_context"> | 3251 | <label for="instruct_bind_to_context" class="checkbox_label flex1" title="Bind to Context
If enabled, Context templates will be automatically selected based on selected Instruct template name or by preference." data-i18n="[title]instruct_bind_to_context"> |
| 3239 | <input id="instruct_bind_to_context" type="checkbox" style="display:none;" /> | 3252 | <input id="instruct_bind_to_context" type="checkbox" style="display:none;" /> |
| 3240 | <small><i class="fa-solid fa-link menu_button margin0"></i></small> | 3253 | <small><i class="fa-solid fa-link menu_button margin0"></i></small> |
| 3241 | </label> | 3254 | </label> |
| 3255 | <label for="instruct_enabled" class="checkbox_label flex1" title="Enable Instruct Mode" data-i18n="[title]instruct_enabled"> | ||
| 3256 | <input id="instruct_enabled" type="checkbox" style="display:none;" /> | ||
| 3257 | <small><i class="fa-solid fa-power-off menu_button margin0"></i></small> | ||
| 3258 | </label> | ||
| 3242 | </div> | 3259 | </div> |
| 3243 | </h4> | 3260 | </h4> |
| 3244 | <div class="flex-container margin0 justifyCenter"> | ||
| 3245 | <input type="file" hidden data-preset-manager-file="instruct" accept=".json, .settings"> | ||
| 3246 | <i id="instruct_set_default" class="menu_button fa-solid fa-heart" title="Auto-select this template on API connection." data-i18n="[title]Auto-select this template on API connection"></i> | ||
| 3247 | <i data-preset-manager-update="instruct" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i> | ||
| 3248 | <i data-preset-manager-new="instruct" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i> | ||
| 3249 | <i data-preset-manager-import="instruct" class=" menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i> | ||
| 3250 | <i data-preset-manager-export="instruct" class=" menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i> | ||
| 3251 | <i data-preset-manager-restore="instruct" class=" menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i> | ||
| 3252 | <i data-preset-manager-delete="instruct" class=" menu_button fa-solid fa-trash-can" title="Delete template" data-i18n="[title]Delete template"></i> | ||
| 3253 | </div> | ||
| 3254 | 3261 | ||
| 3255 | <div class="flex-container" title="Select your current Instruct Template" data-i18n="[title]Select your current Instruct Template"> | 3262 | <div class="flex-container" title="Select your current Instruct Template" data-i18n="[title]Select your current Instruct Template"> |
| 3256 | <select id="instruct_presets" data-preset-manager-for="instruct" class="flex1 text_pole"></select> | 3263 | <select id="instruct_presets" data-preset-manager-for="instruct" class="flex1 text_pole"></select> |
| 3264 | <div class="flex-container margin0 justifyCenter"> | ||
| 3265 | <input type="file" hidden data-preset-manager-file="instruct" accept=".json, .settings"> | ||
| 3266 | <i data-preset-manager-update="instruct" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i> | ||
| 3267 | <i data-preset-manager-new="instruct" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i> | ||
| 3268 | <i data-preset-manager-import="instruct" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i> | ||
| 3269 | <i data-preset-manager-export="instruct" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i> | ||
| 3270 | <i data-preset-manager-restore="instruct" class="menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i> | ||
| 3271 | <i data-preset-manager-delete="instruct" class="menu_button fa-solid fa-trash-can" title="Delete template" data-i18n="[title]Delete template"></i> | ||
| 3272 | </div> | ||
| 3257 | </div> | 3273 | </div> |
| 3258 | <label> | 3274 | <label> |
| 3259 | <small> | 3275 | <small> |
| @@ -3265,14 +3281,6 @@ | |||
| 3265 | <input type="text" id="instruct_activation_regex" class="text_pole textarea_compact" placeholder="e.g. /llama(-)?[3|3.1]/i"> | 3281 | <input type="text" id="instruct_activation_regex" class="text_pole textarea_compact" placeholder="e.g. /llama(-)?[3|3.1]/i"> |
| 3266 | </div> | 3282 | </div> |
| 3267 | <div> | 3283 | <div> |
| 3268 | <label for="instruct_system_prompt" class="flex-container"> | ||
| 3269 | <small data-i18n="System Prompt">System Prompt</small> | ||
| 3270 | <i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="instruct_system_prompt" title="Expand the editor" data-i18n="[title]Expand the editor"></i> | ||
| 3271 | </label> | ||
| 3272 | <textarea id="instruct_system_prompt" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3273 | </div> | ||
| 3274 | |||
| 3275 | <div> | ||
| 3276 | <label for="instruct_wrap" class="checkbox_label"> | 3284 | <label for="instruct_wrap" class="checkbox_label"> |
| 3277 | <input id="instruct_wrap" type="checkbox" /> | 3285 | <input id="instruct_wrap" type="checkbox" /> |
| 3278 | <small data-i18n="Wrap Sequences with Newline">Wrap Sequences with Newline</small> | 3286 | <small data-i18n="Wrap Sequences with Newline">Wrap Sequences with Newline</small> |
| @@ -3285,16 +3293,203 @@ | |||
| 3285 | <input id="instruct_skip_examples" type="checkbox" /> | 3293 | <input id="instruct_skip_examples" type="checkbox" /> |
| 3286 | <small data-i18n="Skip Example Dialogues Formatting">Skip Example Dialogues Formatting</small> | 3294 | <small data-i18n="Skip Example Dialogues Formatting">Skip Example Dialogues Formatting</small> |
| 3287 | </label> | 3295 | </label> |
| 3288 | <label for="instruct_names" class="checkbox_label"> | 3296 | <div> |
| 3289 | <input id="instruct_names" type="checkbox" /> | 3297 | <small data-i18n="Include Names"> |
| 3290 | <small data-i18n="Include Names">Include Names</small> | 3298 | Include Names |
| 3291 | </label> | 3299 | </small> |
| 3292 | <label for="instruct_names_force_groups" class="checkbox_label indent20p"> | 3300 | <select id="instruct_names_behavior"> |
| 3293 | <input id="instruct_names_force_groups" type="checkbox" /> | 3301 | <option value="none" data-i18n="Never">Never</option> |
| 3294 | <small data-i18n="Force for Groups and Personas">Force for Groups and Personas</small> | 3302 | <option value="force" data-i18n="Groups and Past Personas">Groups and Past Personas</option> |
| 3303 | <option value="always" data-i18n="Always">Always</option> | ||
| 3304 | </select> | ||
| 3305 | </div> | ||
| 3306 | </div> | ||
| 3307 | </div> | ||
| 3308 | <div id="InstructSequencesColumn" class="wide100p flexFlowColumn"> | ||
| 3309 | <h4 class="standoutHeader title_restorable"> | ||
| 3310 | <b> | ||
| 3311 | <span data-i18n="Instruct Sequences"> | ||
| 3312 | Instruct Sequences | ||
| 3313 | </span> | ||
| 3314 | </b> | ||
| 3315 | </h4> | ||
| 3316 | <!-- We keep one auto-open so the user would know what is going on in the picked template --> | ||
| 3317 | <details open> | ||
| 3318 | <summary>User Message Sequences</summary> | ||
| 3319 | <div class="flex-container"> | ||
| 3320 | <div class="flexAuto" title="Inserted before a User message and as a last prompt line when impersonating." data-i18n="[title]Inserted before a User message and as a last prompt line when impersonating."> | ||
| 3321 | <small data-i18n="User Prefix">User Message Prefix</small> | ||
| 3322 | <textarea id="instruct_input_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3323 | </div> | ||
| 3324 | <div class="flexAuto" title="Inserted after a User message." data-i18n="[title]Inserted after a User message."> | ||
| 3325 | <small data-i18n="User Suffix">User Message Suffix</small> | ||
| 3326 | <textarea id="instruct_input_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3327 | </div> | ||
| 3328 | </div> | ||
| 3329 | </details> | ||
| 3330 | <details open> | ||
| 3331 | <summary>Assistant Message Sequences</summary> | ||
| 3332 | <div class="flex-container"> | ||
| 3333 | <div class="flexAuto" title="Inserted before an Assistant message and as a last prompt line when generating an AI reply." data-i18n="[title]Inserted before an Assistant message and as a last prompt line when generating an AI reply."> | ||
| 3334 | <small data-i18n="Assistant Prefix">Assistant Message Prefix</small> | ||
| 3335 | <textarea id="instruct_output_sequence" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3336 | </div> | ||
| 3337 | <div class="flexAuto" title="Inserted after an Assistant message." data-i18n="[title]Inserted after an Assistant message."> | ||
| 3338 | <small data-i18n="Assistant Suffix">Assistant Message Suffix</small> | ||
| 3339 | <textarea id="instruct_output_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3340 | </div> | ||
| 3341 | </div> | ||
| 3342 | </details> | ||
| 3343 | <details> | ||
| 3344 | <summary>System Message Sequences</summary> | ||
| 3345 | <div class="flex-container"> | ||
| 3346 | <div class="flexAuto" id="instruct_system_sequence_block" title="Inserted before a System (added by slash commands or extensions) message." data-i18n="[title]Inserted before a System (added by slash commands or extensions) message."> | ||
| 3347 | <small data-i18n="System Prefix">System Message Prefix</small> | ||
| 3348 | <textarea id="instruct_system_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3349 | </div> | ||
| 3350 | <div class="flexAuto" id="instruct_system_suffix_block" title="Inserted after a System message." data-i18n="[title]Inserted after a System message."> | ||
| 3351 | <small data-i18n="System Suffix">System Message Suffix</small> | ||
| 3352 | <textarea id="instruct_system_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3353 | </div> | ||
| 3354 | </div> | ||
| 3355 | <div class="flexBasis100p" title="If enabled, System Sequences will be the same as User Sequences." data-i18n="[title]If enabled, System Sequences will be the same as User Sequences."> | ||
| 3356 | <label class="checkbox_label" for="instruct_system_same_as_user"> | ||
| 3357 | <input id="instruct_system_same_as_user" type="checkbox" /> | ||
| 3358 | <small data-i18n="System same as User">System same as User</small> | ||
| 3359 | </label> | ||
| 3360 | </div> | ||
| 3361 | </details> | ||
| 3362 | <details> | ||
| 3363 | <summary>System Prompt Sequences</summary> | ||
| 3364 | <div class="flex-container"> | ||
| 3365 | <div class="flexAuto" title="Inserted before a System prompt." data-i18n="[title]Inserted before a System prompt."> | ||
| 3366 | <label for="instruct_system_sequence_prefix"> | ||
| 3367 | <small data-i18n="System Prompt Prefix">System Prompt Prefix</small> | ||
| 3368 | </label> | ||
| 3369 | <div> | ||
| 3370 | <textarea id="instruct_system_sequence_prefix" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3371 | </div> | ||
| 3372 | </div> | ||
| 3373 | <div class="flexAuto" title="Inserted after a System prompt." data-i18n="[title]Inserted after a System prompt."> | ||
| 3374 | <label for="instruct_system_sequence_suffix"> | ||
| 3375 | <small data-i18n="System Prompt Suffix">System Prompt Suffix</small> | ||
| 3376 | </label> | ||
| 3377 | <div> | ||
| 3378 | <textarea id="instruct_system_sequence_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3379 | </div> | ||
| 3380 | </div> | ||
| 3381 | </div> | ||
| 3382 | </details> | ||
| 3383 | <details> | ||
| 3384 | <summary data-i18n="Misc. Sequences">Misc. Sequences</summary> | ||
| 3385 | <div class="flex-container"> | ||
| 3386 | <div class="flexAuto" title="Inserted before the first Assistant's message." data-i18n="[title]Inserted before the first Assistant's message."> | ||
| 3387 | <small data-i18n="First Assistant Prefix">First Assistant Prefix</small> | ||
| 3388 | <textarea id="instruct_first_output_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3389 | </div> | ||
| 3390 | <div class="flexAuto" title="Inserted before the last Assistant's message or as a last prompt line when generating an AI reply (except a neutral/system role)." data-i18n="[title]instruct_last_output_sequence"> | ||
| 3391 | <small data-i18n="Last Assistant Prefix">Last Assistant Prefix</small> | ||
| 3392 | <textarea id="instruct_last_output_sequence" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3393 | </div> | ||
| 3394 | </div> | ||
| 3395 | <div class="flex-container"> | ||
| 3396 | <div class="flexAuto" title="Inserted before the first User's message." data-i18n="[title]Inserted before the first User's message."> | ||
| 3397 | <small data-i18n="First User Prefix">First User Prefix</small> | ||
| 3398 | <textarea id="instruct_first_input_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3399 | </div> | ||
| 3400 | <div class="flexAuto" title="Inserted before the last User's message." data-i18n="[title]instruct_last_input_sequence"> | ||
| 3401 | <small data-i18n="Last User Prefix">Last User Prefix</small> | ||
| 3402 | <textarea id="instruct_last_input_sequence" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3403 | </div> | ||
| 3404 | </div> | ||
| 3405 | <div class="flex-container"> | ||
| 3406 | <div class="flexAuto" title="Will be inserted as a last prompt line when using system/neutral generation." data-i18n="[title]Will be inserted as a last prompt line when using system/neutral generation."> | ||
| 3407 | <small data-i18n="System Instruction Prefix">System Instruction Prefix</small> | ||
| 3408 | <textarea id="instruct_last_system_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3409 | </div> | ||
| 3410 | <div class="flexAuto" title="If a stop sequence is generated, everything past it will be removed from the output (inclusive)." data-i18n="[title]If a stop sequence is generated, everything past it will be removed from the output (inclusive)."> | ||
| 3411 | <small data-i18n="Stop Sequence">Stop Sequence</small> | ||
| 3412 | <textarea id="instruct_stop_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3413 | </div> | ||
| 3414 | </div> | ||
| 3415 | <div class="flex-container"> | ||
| 3416 | <div class="flexAuto" title="Will be inserted at the start of the chat history if it doesn't start with a User message." data-i18n="[title]Will be inserted at the start of the chat history if it doesn't start with a User message."> | ||
| 3417 | <small data-i18n="User Filler Message">User Filler Message</small> | ||
| 3418 | <textarea id="instruct_user_alignment_message" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3419 | </div> | ||
| 3420 | </div> | ||
| 3421 | </details> | ||
| 3422 | </div> | ||
| 3423 | </div> | ||
| 3424 | <div id="SystemPromptColumn" class="flex-container flexNoGap flexFlowColumn flex1"> | ||
| 3425 | <div id="SystemPromptBlock"> | ||
| 3426 | <h4 class="standoutHeader title_restorable justifySpaceBetween"> | ||
| 3427 | <div class="flex-container"> | ||
| 3428 | <span data-i18n="System Prompt">System Prompt</span> | ||
| 3429 | <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#system-prompt" class="notes-link" target="_blank"> | ||
| 3430 | <span class="fa-solid fa-circle-question note-link-span"></span> | ||
| 3431 | </a> | ||
| 3432 | </div> | ||
| 3433 | <div class="flex-container"> | ||
| 3434 | <label for="sysprompt_enabled" class="checkbox_label flex1" title="Enable System Prompt" data-i18n="[title]sysprompt_enabled"> | ||
| 3435 | <input id="sysprompt_enabled" type="checkbox" style="display:none;" /> | ||
| 3436 | <small><i class="fa-solid fa-power-off menu_button margin0"></i></small> | ||
| 3437 | </label> | ||
| 3438 | </div> | ||
| 3439 | </h4> | ||
| 3440 | |||
| 3441 | <div class="flex-container" title="Select your current System Prompt" data-i18n="[title]Select your current System Prompt"> | ||
| 3442 | <select id="sysprompt_select" data-preset-manager-for="sysprompt" class="flex1 text_pole"></select> | ||
| 3443 | <div class="flex-container margin0 justifyCenter"> | ||
| 3444 | <input type="file" hidden data-preset-manager-file="sysprompt" accept=".json, .settings"> | ||
| 3445 | <i data-preset-manager-update="sysprompt" class="menu_button fa-solid fa-save" title="Update current prompt" data-i18n="[title]Update current prompt"></i> | ||
| 3446 | <i data-preset-manager-new="sysprompt" class="menu_button fa-solid fa-file-circle-plus" title="Save prompt as" data-i18n="[title]Save prompt as"></i> | ||
| 3447 | <i data-preset-manager-import="sysprompt" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i> | ||
| 3448 | <i data-preset-manager-export="sysprompt" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i> | ||
| 3449 | <i data-preset-manager-restore="sysprompt" class="menu_button fa-solid fa-recycle" title="Restore current prompt" data-i18n="[title]Restore current prompt"></i> | ||
| 3450 | <i data-preset-manager-delete="sysprompt" class="menu_button fa-solid fa-trash-can" title="Delete prompt" data-i18n="[title]Delete prompt"></i> | ||
| 3451 | </div> | ||
| 3452 | </div> | ||
| 3453 | |||
| 3454 | <div> | ||
| 3455 | <label for="sysprompt_content" class="flex-container"> | ||
| 3456 | <small data-i18n="Prompt Content">Prompt Content</small> | ||
| 3457 | <i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="sysprompt_content" title="Expand the editor" data-i18n="[title]Expand the editor"></i> | ||
| 3295 | </label> | 3458 | </label> |
| 3459 | <textarea id="sysprompt_content" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3460 | </div> | ||
| 3461 | </div> | ||
| 3462 | |||
| 3463 | <div> | ||
| 3464 | | ||
| 3465 | </div> | ||
| 3466 | |||
| 3467 | <div> | ||
| 3468 | <h4 class="range-block-title justifyLeft standoutHeader"> | ||
| 3469 | <span data-i18n="Custom Stopping Strings"> | ||
| 3470 | Custom Stopping Strings | ||
| 3471 | </span> | ||
| 3472 | <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#custom-stopping-strings" class="notes-link" target="_blank"> | ||
| 3473 | <span class="fa-solid fa-circle-question note-link-span"></span> | ||
| 3474 | </a> | ||
| 3475 | </h4> | ||
| 3476 | <div> | ||
| 3477 | <small> | ||
| 3478 | <span data-i18n="JSON serialized array of strings">JSON serialized array of strings</span> | ||
| 3479 | <i class="fa-solid fa-question-circle opacity50p" title="e.g: ["Ford", "BMW", "Fiat"]"></i> | ||
| 3480 | </small> | ||
| 3481 | </div> | ||
| 3482 | <div> | ||
| 3483 | <textarea id="custom_stopping_strings" class="text_pole textarea_compact monospace autoSetHeight"></textarea> | ||
| 3296 | </div> | 3484 | </div> |
| 3485 | <label class="checkbox_label" for="custom_stopping_strings_macro"> | ||
| 3486 | <input id="custom_stopping_strings_macro" type="checkbox" checked> | ||
| 3487 | <small data-i18n="Replace Macro in Custom Stopping Strings"> | ||
| 3488 | Replace Macro in Custom Stopping Strings | ||
| 3489 | </small> | ||
| 3490 | </label> | ||
| 3297 | </div> | 3491 | </div> |
| 3492 | |||
| 3298 | <div name="tokenizerSettingsBlock"> | 3493 | <div name="tokenizerSettingsBlock"> |
| 3299 | <div name="tokenizerSelectorBlock"> | 3494 | <div name="tokenizerSelectorBlock"> |
| 3300 | <h4 class="standoutHeader"><span data-i18n="Tokenizer">Tokenizer</span> | 3495 | <h4 class="standoutHeader"><span data-i18n="Tokenizer">Tokenizer</span> |
| @@ -3315,7 +3510,8 @@ | |||
| 3315 | <option value="16">Command-R</option> | 3510 | <option value="16">Command-R</option> |
| 3316 | <option value="4">NerdStash (NovelAI Clio)</option> | 3511 | <option value="4">NerdStash (NovelAI Clio)</option> |
| 3317 | <option value="5">NerdStash v2 (NovelAI Kayra)</option> | 3512 | <option value="5">NerdStash v2 (NovelAI Kayra)</option> |
| 3318 | <option value="7">Mistral</option> | 3513 | <option value="7">Mistral V1</option> |
| 3514 | <option value="17">Mistral Nemo</option> | ||
| 3319 | <option value="8">Yi</option> | 3515 | <option value="8">Yi</option> |
| 3320 | <option value="11">Claude 1/2</option> | 3516 | <option value="11">Claude 1/2</option> |
| 3321 | <option value="6">API (WebUI / koboldcpp)</option> | 3517 | <option value="6">API (WebUI / koboldcpp)</option> |
| @@ -3365,114 +3561,6 @@ | |||
| 3365 | </div> | 3561 | </div> |
| 3366 | </div> | 3562 | </div> |
| 3367 | </div> | 3563 | </div> |
| 3368 | <div id="InstructSequencesColumn" class="flex-container flexNoGap flexFlowColumn flex1"> | ||
| 3369 | <div class="wide100p flexFlowColumn"> | ||
| 3370 | <h4 class="standoutHeader title_restorable"> | ||
| 3371 | <b> | ||
| 3372 | <span data-i18n="Instruct Sequences"> | ||
| 3373 | Instruct Sequences | ||
| 3374 | </span> | ||
| 3375 | <small data-i18n="(Saves to Template)"> | ||
| 3376 | (Saves to Template) | ||
| 3377 | </small> | ||
| 3378 | </b> | ||
| 3379 | </h4> | ||
| 3380 | <div class="flex-container"> | ||
| 3381 | <div class="flexAuto" title="Inserted before a System prompt." data-i18n="[title]Inserted before a System prompt."> | ||
| 3382 | <label for="instruct_system_sequence_prefix"> | ||
| 3383 | <small data-i18n="System Prompt Prefix">System Prompt Prefix</small> | ||
| 3384 | </label> | ||
| 3385 | <div> | ||
| 3386 | <textarea id="instruct_system_sequence_prefix" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3387 | </div> | ||
| 3388 | </div> | ||
| 3389 | <div class="flexAuto" title="Inserted after a System prompt." data-i18n="[title]Inserted after a System prompt."> | ||
| 3390 | <label for="instruct_system_sequence_suffix"> | ||
| 3391 | <small data-i18n="System Prompt Suffix">System Prompt Suffix</small> | ||
| 3392 | </label> | ||
| 3393 | <div> | ||
| 3394 | <textarea id="instruct_system_sequence_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3395 | </div> | ||
| 3396 | </div> | ||
| 3397 | </div> | ||
| 3398 | <div class="flex-container"> | ||
| 3399 | <div class="flexAuto" title="Inserted before a User message and as a last prompt line when impersonating." data-i18n="[title]Inserted before a User message and as a last prompt line when impersonating."> | ||
| 3400 | <small data-i18n="User Prefix">User Message Prefix</small> | ||
| 3401 | <textarea id="instruct_input_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3402 | </div> | ||
| 3403 | <div class="flexAuto" title="Inserted after a User message." data-i18n="[title]Inserted after a User message."> | ||
| 3404 | <small data-i18n="User Suffix">User Message Suffix</small> | ||
| 3405 | <textarea id="instruct_input_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3406 | </div> | ||
| 3407 | </div> | ||
| 3408 | <div class="flex-container"> | ||
| 3409 | <div class="flexAuto" title="Inserted before an Assistant message and as a last prompt line when generating an AI reply." data-i18n="[title]Inserted before an Assistant message and as a last prompt line when generating an AI reply."> | ||
| 3410 | <small data-i18n="Assistant Prefix">Assistant Message Prefix</small> | ||
| 3411 | <textarea id="instruct_output_sequence" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3412 | </div> | ||
| 3413 | <div class="flexAuto" title="Inserted after an Assistant message." data-i18n="[title]Inserted after an Assistant message."> | ||
| 3414 | <small data-i18n="Assistant Suffix">Assistant Message Suffix</small> | ||
| 3415 | <textarea id="instruct_output_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3416 | </div> | ||
| 3417 | </div> | ||
| 3418 | <div class="flex-container"> | ||
| 3419 | <div class="flexAuto" id="instruct_system_sequence_block" title="Inserted before a System (added by slash commands or extensions) message." data-i18n="[title]Inserted before a System (added by slash commands or extensions) message."> | ||
| 3420 | <small data-i18n="System Prefix">System Message Prefix</small> | ||
| 3421 | <textarea id="instruct_system_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3422 | </div> | ||
| 3423 | <div class="flexAuto" id="instruct_system_suffix_block" title="Inserted after a System message." data-i18n="[title]Inserted after a System message."> | ||
| 3424 | <small data-i18n="System Suffix">System Message Suffix</small> | ||
| 3425 | <textarea id="instruct_system_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3426 | </div> | ||
| 3427 | </div> | ||
| 3428 | <div class="flexBasis100p" title="If enabled, System Sequences will be the same as User Sequences." data-i18n="[title]If enabled, System Sequences will be the same as User Sequences."> | ||
| 3429 | <label class="checkbox_label" for="instruct_system_same_as_user"> | ||
| 3430 | <input id="instruct_system_same_as_user" type="checkbox" /> | ||
| 3431 | <small data-i18n="System same as User">System same as User</small> | ||
| 3432 | </label> | ||
| 3433 | </div> | ||
| 3434 | |||
| 3435 | <h5 class="textAlignCenter" data-i18n="Misc. Sequences"> | ||
| 3436 | Misc. Sequences | ||
| 3437 | </h5> | ||
| 3438 | <div class="flex-container"> | ||
| 3439 | <div class="flexAuto" title="Inserted before the first Assistant's message." data-i18n="[title]Inserted before the first Assistant's message."> | ||
| 3440 | <small data-i18n="First Assistant Prefix">First Assistant Prefix</small> | ||
| 3441 | <textarea id="instruct_first_output_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3442 | </div> | ||
| 3443 | <div class="flexAuto" title="Inserted before the last Assistant's message or as a last prompt line when generating an AI reply (except a neutral/system role)." data-i18n="[title]instruct_last_output_sequence"> | ||
| 3444 | <small data-i18n="Last Assistant Prefix">Last Assistant Prefix</small> | ||
| 3445 | <textarea id="instruct_last_output_sequence" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3446 | </div> | ||
| 3447 | </div> | ||
| 3448 | <div class="flex-container"> | ||
| 3449 | <div class="flexAuto" title="Inserted before the first User's message." data-i18n="[title]Inserted before the first User's message."> | ||
| 3450 | <small data-i18n="First User Prefix">First User Prefix</small> | ||
| 3451 | <textarea id="instruct_first_input_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3452 | </div> | ||
| 3453 | <div class="flexAuto" title="Inserted before the last User's message." data-i18n="[title]instruct_last_input_sequence"> | ||
| 3454 | <small data-i18n="Last User Prefix">Last User Prefix</small> | ||
| 3455 | <textarea id="instruct_last_input_sequence" class="text_pole wide100p textarea_compact autoSetHeight"></textarea> | ||
| 3456 | </div> | ||
| 3457 | </div> | ||
| 3458 | <div class="flex-container"> | ||
| 3459 | <div class="flexAuto" title="Will be inserted as a last prompt line when using system/neutral generation." data-i18n="[title]Will be inserted as a last prompt line when using system/neutral generation."> | ||
| 3460 | <small data-i18n="System Instruction Prefix">System Instruction Prefix</small> | ||
| 3461 | <textarea id="instruct_last_system_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3462 | </div> | ||
| 3463 | <div class="flexAuto" title="If a stop sequence is generated, everything past it will be removed from the output (inclusive)." data-i18n="[title]If a stop sequence is generated, everything past it will be removed from the output (inclusive)."> | ||
| 3464 | <small data-i18n="Stop Sequence">Stop Sequence</small> | ||
| 3465 | <textarea id="instruct_stop_sequence" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3466 | </div> | ||
| 3467 | </div> | ||
| 3468 | <div class="flex-container"> | ||
| 3469 | <div class="flexAuto" title="Will be inserted at the start of the chat history if it doesn't start with a User message." data-i18n="[title]Will be inserted at the start of the chat history if it doesn't start with a User message."> | ||
| 3470 | <small data-i18n="User Filler Message">User Filler Message</small> | ||
| 3471 | <textarea id="instruct_user_alignment_message" class="text_pole textarea_compact autoSetHeight"></textarea> | ||
| 3472 | </div> | ||
| 3473 | </div> | ||
| 3474 | </div> | ||
| 3475 | </div> | ||
| 3476 | </div> | 3564 | </div> |
| 3477 | </div> | 3565 | </div> |
| 3478 | </div> | 3566 | </div> |
| @@ -5452,23 +5540,23 @@ | |||
| 5452 | <div class="world_entry_form_control flex1"> | 5540 | <div class="world_entry_form_control flex1"> |
| 5453 | <small class="textAlignCenter" data-i18n="Case-Sensitive">Case-Sensitive</small> | 5541 | <small class="textAlignCenter" data-i18n="Case-Sensitive">Case-Sensitive</small> |
| 5454 | <select name="caseSensitive" class="text_pole widthNatural margin0"> | 5542 | <select name="caseSensitive" class="text_pole widthNatural margin0"> |
| 5455 | <option value="null" data-i18n="Use global setting">Use global setting</option> | 5543 | <option value="null" data-i18n="Use global">Use global</option> |
| 5456 | <option value="true" data-i18n="Yes">Yes</option> | 5544 | <option value="true" data-i18n="Yes">Yes</option> |
| 5457 | <option value="false" data-i18n="No">No</option> | 5545 | <option value="false" data-i18n="No">No</option> |
| 5458 | </select> | 5546 | </select> |
| 5459 | </div> | 5547 | </div> |
| 5460 | <div class="world_entry_form_control flex1"> | 5548 | <div class="world_entry_form_control flex1"> |
| 5461 | <small class="textAlignCenter" data-i18n="Match Whole Words">Match Whole Words</small> | 5549 | <small class="textAlignCenter" data-i18n="Whole Words">Whole Words</small> |
| 5462 | <select name="matchWholeWords" class="text_pole widthNatural margin0"> | 5550 | <select name="matchWholeWords" class="text_pole widthNatural margin0"> |
| 5463 | <option value="null" data-i18n="Use global setting">Use global setting</option> | 5551 | <option value="null" data-i18n="Use global">Use global</option> |
| 5464 | <option value="true" data-i18n="Yes">Yes</option> | 5552 | <option value="true" data-i18n="Yes">Yes</option> |
| 5465 | <option value="false" data-i18n="No">No</option> | 5553 | <option value="false" data-i18n="No">No</option> |
| 5466 | </select> | 5554 | </select> |
| 5467 | </div> | 5555 | </div> |
| 5468 | <div class="world_entry_form_control flex1"> | 5556 | <div class="world_entry_form_control flex1"> |
| 5469 | <small class="textAlignCenter" data-i18n="Use Group Scoring">Use Group Scoring</small> | 5557 | <small class="textAlignCenter" data-i18n="Group Scoring">Group Scoring</small> |
| 5470 | <select name="useGroupScoring" class="text_pole widthNatural margin0"> | 5558 | <select name="useGroupScoring" class="text_pole widthNatural margin0"> |
| 5471 | <option value="null" data-i18n="Use global setting">Use global setting</option> | 5559 | <option value="null" data-i18n="Use global">Use global</option> |
| 5472 | <option value="true" data-i18n="Yes">Yes</option> | 5560 | <option value="true" data-i18n="Yes">Yes</option> |
| 5473 | <option value="false" data-i18n="No">No</option> | 5561 | <option value="false" data-i18n="No">No</option> |
| 5474 | </select> | 5562 | </select> |
| @@ -5477,6 +5565,13 @@ | |||
| 5477 | <small class="textAlignCenter" data-i18n="Automation ID">Automation ID</small> | 5565 | <small class="textAlignCenter" data-i18n="Automation ID">Automation ID</small> |
| 5478 | <input class="text_pole margin0" name="automationId" type="text" placeholder="( None )" data-i18n="[placeholder]( None )"> | 5566 | <input class="text_pole margin0" name="automationId" type="text" placeholder="( None )" data-i18n="[placeholder]( None )"> |
| 5479 | </div> | 5567 | </div> |
| 5568 | <div class="world_entry_form_control flex1" title="Defines delay levels for recursive scans. Initially, only the first level (smallest number) will match. Once no matches are found, the next level becomes eligible for matching. This repeats until all levels are checked. Tied to the "Delay until recursion" setting." data-i18n="[title]delay_until_recursion_level"> | ||
| 5569 | <small class="textAlignCenter"> | ||
| 5570 | <span data-i18n="Recursion Level">Recursion Level</span> | ||
| 5571 | <div class="fa-solid fa-circle-info opacity50p"></div> | ||
| 5572 | </small> | ||
| 5573 | <input class="text_pole margin0" name="delayUntilRecursionLevel" type="text" placeholder="1"> | ||
| 5574 | </div> | ||
| 5480 | </div> | 5575 | </div> |
| 5481 | <div name="contentAndCharFilterBlock" class="world_entry_thin_controls flex2"> | 5576 | <div name="contentAndCharFilterBlock" class="world_entry_thin_controls flex2"> |
| 5482 | <div class="world_entry_form_control flex1"> | 5577 | <div class="world_entry_form_control flex1"> |
| @@ -5493,20 +5588,20 @@ | |||
| 5493 | <div> | 5588 | <div> |
| 5494 | <label class="checkbox flex-container alignitemscenter flexNoGap"> | 5589 | <label class="checkbox flex-container alignitemscenter flexNoGap"> |
| 5495 | <input type="checkbox" name="exclude_recursion" /> | 5590 | <input type="checkbox" name="exclude_recursion" /> |
| 5496 | <span data-i18n="Exclude from recursion"> | 5591 | <span data-i18n="Non-recursable (will not be activated by another)"> |
| 5497 | Non-recursable (this entry will not be activated by another) | 5592 | Non-recursable (will not be activated by another) |
| 5498 | </span> | 5593 | </span> |
| 5499 | </label> | 5594 | </label> |
| 5500 | <label class="checkbox flex-container alignitemscenter flexNoGap"> | 5595 | <label class="checkbox flex-container alignitemscenter flexNoGap"> |
| 5501 | <input type="checkbox" name="prevent_recursion" /> | 5596 | <input type="checkbox" name="prevent_recursion" /> |
| 5502 | <span data-i18n="Prevent further recursion (this entry will not activate others)"> | 5597 | <span data-i18n="Prevent further recursion (this entry will not activate others)"> |
| 5503 | Prevent further recursion (this entry will not activate others) | 5598 | Prevent further recursion (will not activate others) |
| 5504 | </span> | 5599 | </span> |
| 5505 | </label> | 5600 | </label> |
| 5506 | <label class="checkbox flex-container alignitemscenter flexNoGap"> | 5601 | <label class="checkbox flex-container alignitemscenter flexNoGap"> |
| 5507 | <input type="checkbox" name="delay_until_recursion" /> | 5602 | <input type="checkbox" name="delay_until_recursion" /> |
| 5508 | <span data-i18n="Delay until recursion (this entry can only be activated on recursive checking)"> | 5603 | <span data-i18n="Delay until recursion (can only be activated on recursive checking)"> |
| 5509 | Delay until recursion (this entry can only be activated on recursive checking) | 5604 | Delay until recursion (can only be activated on recursive checking) |
| 5510 | </span> | 5605 | </span> |
| 5511 | </label> | 5606 | </label> |
| 5512 | </div> | 5607 | </div> |
| @@ -99,7 +99,7 @@ import { | |||
| 99 | proxies, | 99 | proxies, |
| 100 | loadProxyPresets, | 100 | loadProxyPresets, |
| 101 | selected_proxy, | 101 | selected_proxy, |
| 102 | initOpenai, | 102 | initOpenAI, |
| 103 | } from './scripts/openai.js'; | 103 | } from './scripts/openai.js'; |
| 104 | 104 | ||
| 105 | import { | 105 | import { |
| @@ -210,7 +210,7 @@ import { | |||
| 210 | selectContextPreset, | 210 | selectContextPreset, |
| 211 | } from './scripts/instruct-mode.js'; | 211 | } from './scripts/instruct-mode.js'; |
| 212 | import { initLocales, t, translate } from './scripts/i18n.js'; | 212 | import { initLocales, t, translate } from './scripts/i18n.js'; |
| 213 | import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, getTokenizerModel, initTokenizers, saveTokenCache } from './scripts/tokenizers.js'; | 213 | import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, getTokenizerModel, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js'; |
| 214 | import { | 214 | import { |
| 215 | user_avatar, | 215 | user_avatar, |
| 216 | getUserAvatars, | 216 | getUserAvatars, |
| @@ -224,7 +224,7 @@ import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_set | |||
| 224 | import { hideLoader, showLoader } from './scripts/loader.js'; | 224 | import { hideLoader, showLoader } from './scripts/loader.js'; |
| 225 | import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js'; | 225 | import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js'; |
| 226 | import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels } from './scripts/textgen-models.js'; | 226 | import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels } from './scripts/textgen-models.js'; |
| 227 | import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId } from './scripts/chats.js'; | 227 | import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js'; |
| 228 | import { initPresetManager } from './scripts/preset-manager.js'; | 228 | import { initPresetManager } from './scripts/preset-manager.js'; |
| 229 | import { MacrosParser, evaluateMacros, getLastMessageId } from './scripts/macros.js'; | 229 | import { MacrosParser, evaluateMacros, getLastMessageId } from './scripts/macros.js'; |
| 230 | import { currentUser, setUserControls } from './scripts/user.js'; | 230 | import { currentUser, setUserControls } from './scripts/user.js'; |
| @@ -243,6 +243,7 @@ import { SlashCommandEnumValue, enumTypes } from './scripts/slash-commands/Slash | |||
| 243 | import { commonEnumProviders, enumIcons } from './scripts/slash-commands/SlashCommandCommonEnumsProvider.js'; | 243 | import { commonEnumProviders, enumIcons } from './scripts/slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 244 | import { initInputMarkdown } from './scripts/input-md-formatting.js'; | 244 | import { initInputMarkdown } from './scripts/input-md-formatting.js'; |
| 245 | import { AbortReason } from './scripts/util/AbortReason.js'; | 245 | import { AbortReason } from './scripts/util/AbortReason.js'; |
| 246 | import { initSystemPrompts } from './scripts/sysprompt.js'; | ||
| 246 | 247 | ||
| 247 | //exporting functions and vars for mods | 248 | //exporting functions and vars for mods |
| 248 | export { | 249 | export { |
| @@ -411,6 +412,7 @@ export const event_types = { | |||
| 411 | MESSAGE_FILE_EMBEDDED: 'message_file_embedded', | 412 | MESSAGE_FILE_EMBEDDED: 'message_file_embedded', |
| 412 | IMPERSONATE_READY: 'impersonate_ready', | 413 | IMPERSONATE_READY: 'impersonate_ready', |
| 413 | CHAT_CHANGED: 'chat_id_changed', | 414 | CHAT_CHANGED: 'chat_id_changed', |
| 415 | GENERATION_AFTER_COMMANDS: 'GENERATION_AFTER_COMMANDS', | ||
| 414 | GENERATION_STARTED: 'generation_started', | 416 | GENERATION_STARTED: 'generation_started', |
| 415 | GENERATION_STOPPED: 'generation_stopped', | 417 | GENERATION_STOPPED: 'generation_stopped', |
| 416 | GENERATION_ENDED: 'generation_ended', | 418 | GENERATION_ENDED: 'generation_ended', |
| @@ -509,6 +511,7 @@ let saveCharactersPage = 0; | |||
| 509 | export const default_avatar = 'img/ai4.png'; | 511 | export const default_avatar = 'img/ai4.png'; |
| 510 | export const system_avatar = 'img/five.png'; | 512 | export const system_avatar = 'img/five.png'; |
| 511 | export const comment_avatar = 'img/quill.png'; | 513 | export const comment_avatar = 'img/quill.png'; |
| 514 | export const default_user_avatar = 'img/user-default.png'; | ||
| 512 | export let CLIENT_VERSION = 'SillyTavern:UNKNOWN:Cohee#1207'; // For Horde header | 515 | export let CLIENT_VERSION = 'SillyTavern:UNKNOWN:Cohee#1207'; // For Horde header |
| 513 | let optionsPopper = Popper.createPopper(document.getElementById('options_button'), document.getElementById('options'), { | 516 | let optionsPopper = Popper.createPopper(document.getElementById('options_button'), document.getElementById('options'), { |
| 514 | placement: 'top-start', | 517 | placement: 'top-start', |
| @@ -927,9 +930,12 @@ async function firstLoadInit() { | |||
| 927 | addSafariPatch(); | 930 | addSafariPatch(); |
| 928 | await getClientVersion(); | 931 | await getClientVersion(); |
| 929 | await readSecretState(); | 932 | await readSecretState(); |
| 930 | initLocales(); | 933 | await initLocales(); |
| 931 | initDefaultSlashCommands(); | 934 | initDefaultSlashCommands(); |
| 932 | initTextGenModels(); | 935 | initTextGenModels(); |
| 936 | initOpenAI(); | ||
| 937 | initSystemPrompts(); | ||
| 938 | await initPresetManager(); | ||
| 933 | await getSystemMessages(); | 939 | await getSystemMessages(); |
| 934 | sendSystemMessage(system_message_types.WELCOME); | 940 | sendSystemMessage(system_message_types.WELCOME); |
| 935 | sendSystemMessage(system_message_types.WELCOME_PROMPT); | 941 | sendSystemMessage(system_message_types.WELCOME_PROMPT); |
| @@ -937,13 +943,11 @@ async function firstLoadInit() { | |||
| 937 | initKeyboard(); | 943 | initKeyboard(); |
| 938 | initDynamicStyles(); | 944 | initDynamicStyles(); |
| 939 | initTags(); | 945 | initTags(); |
| 940 | initOpenai(); | ||
| 941 | initBookmarks(); | 946 | initBookmarks(); |
| 942 | await getUserAvatars(true, user_avatar); | 947 | await getUserAvatars(true, user_avatar); |
| 943 | await getCharacters(); | 948 | await getCharacters(); |
| 944 | await getBackgrounds(); | 949 | await getBackgrounds(); |
| 945 | await initTokenizers(); | 950 | await initTokenizers(); |
| 946 | await initPresetManager(); | ||
| 947 | initBackgrounds(); | 951 | initBackgrounds(); |
| 948 | initAuthorsNote(); | 952 | initAuthorsNote(); |
| 949 | initPersonas(); | 953 | initPersonas(); |
| @@ -1213,6 +1217,9 @@ async function getStatusTextgen() { | |||
| 1213 | // Determine instruct mode preset | 1217 | // Determine instruct mode preset |
| 1214 | autoSelectInstructPreset(online_status); | 1218 | autoSelectInstructPreset(online_status); |
| 1215 | 1219 | ||
| 1220 | const supportsTokenization = response.headers.get('x-supports-tokenization') === 'true'; | ||
| 1221 | supportsTokenization ? sessionStorage.setItem(TOKENIZER_SUPPORTED_KEY, 'true') : sessionStorage.removeItem(TOKENIZER_SUPPORTED_KEY); | ||
| 1222 | |||
| 1216 | // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress. | 1223 | // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress. |
| 1217 | if (online_status === 'no_connection' && data.response) { | 1224 | if (online_status === 'no_connection' && data.response) { |
| 1218 | toastr.error(data.response, 'API Error', { timeOut: 5000, preventDuplicates: true }); | 1225 | toastr.error(data.response, 'API Error', { timeOut: 5000, preventDuplicates: true }); |
| @@ -1845,6 +1852,7 @@ export async function deleteLastMessage() { | |||
| 1845 | } | 1852 | } |
| 1846 | 1853 | ||
| 1847 | export async function reloadCurrentChat() { | 1854 | export async function reloadCurrentChat() { |
| 1855 | preserveNeutralChat(); | ||
| 1848 | await clearChat(); | 1856 | await clearChat(); |
| 1849 | chat.length = 0; | 1857 | chat.length = 0; |
| 1850 | 1858 | ||
| @@ -1856,6 +1864,7 @@ export async function reloadCurrentChat() { | |||
| 1856 | } | 1864 | } |
| 1857 | else { | 1865 | else { |
| 1858 | resetChatState(); | 1866 | resetChatState(); |
| 1867 | restoreNeutralChat(); | ||
| 1859 | await getCharacters(); | 1868 | await getCharacters(); |
| 1860 | await printMessages(); | 1869 | await printMessages(); |
| 1861 | await eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId()); | 1870 | await eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId()); |
| @@ -3332,10 +3341,12 @@ function removeLastMessage() { | |||
| 3332 | */ | 3341 | */ |
| 3333 | export async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage, quietName } = {}, dryRun = false) { | 3342 | export async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage, quietName } = {}, dryRun = false) { |
| 3334 | console.log('Generate entered'); | 3343 | console.log('Generate entered'); |
| 3335 | await eventSource.emit(event_types.GENERATION_STARTED, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun); | ||
| 3336 | setGenerationProgress(0); | 3344 | setGenerationProgress(0); |
| 3337 | generation_started = new Date(); | 3345 | generation_started = new Date(); |
| 3338 | 3346 | ||
| 3347 | // Occurs every time, even if the generation is aborted due to slash commands execution | ||
| 3348 | await eventSource.emit(event_types.GENERATION_STARTED, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun); | ||
| 3349 | |||
| 3339 | // Don't recreate abort controller if signal is passed | 3350 | // Don't recreate abort controller if signal is passed |
| 3340 | if (!(abortController && signal)) { | 3351 | if (!(abortController && signal)) { |
| 3341 | abortController = new AbortController(); | 3352 | abortController = new AbortController(); |
| @@ -3355,6 +3366,9 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3355 | } | 3366 | } |
| 3356 | } | 3367 | } |
| 3357 | 3368 | ||
| 3369 | // Occurs only if the generation is not aborted due to slash commands execution | ||
| 3370 | await eventSource.emit(event_types.GENERATION_AFTER_COMMANDS, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun); | ||
| 3371 | |||
| 3358 | if (main_api == 'kobold' && kai_settings.streaming_kobold && !kai_flags.can_use_streaming) { | 3372 | if (main_api == 'kobold' && kai_settings.streaming_kobold && !kai_flags.can_use_streaming) { |
| 3359 | toastr.error('Streaming is enabled, but the version of Kobold used does not support token streaming.', undefined, { timeOut: 10000, preventDuplicates: true }); | 3373 | toastr.error('Streaming is enabled, but the version of Kobold used does not support token streaming.', undefined, { timeOut: 10000, preventDuplicates: true }); |
| 3360 | unblockGeneration(type); | 3374 | unblockGeneration(type); |
| @@ -3512,9 +3526,14 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3512 | jailbreak, | 3526 | jailbreak, |
| 3513 | } = getCharacterCardFields(); | 3527 | } = getCharacterCardFields(); |
| 3514 | 3528 | ||
| 3515 | if (isInstruct) { | 3529 | if (main_api !== 'openai') { |
| 3516 | system = power_user.prefer_character_prompt && system ? system : baseChatReplace(power_user.instruct.system_prompt, name1, name2); | 3530 | if (power_user.sysprompt.enabled) { |
| 3517 | system = formatInstructModeSystemPrompt(substituteParams(system, name1, name2, power_user.instruct.system_prompt)); | 3531 | system = power_user.prefer_character_prompt && system ? system : baseChatReplace(power_user.sysprompt.content, name1, name2); |
| 3532 | system = isInstruct ? formatInstructModeSystemPrompt(substituteParams(system, name1, name2, power_user.sysprompt.content)) : system; | ||
| 3533 | } else { | ||
| 3534 | // Nullify if it's not enabled | ||
| 3535 | system = ''; | ||
| 3536 | } | ||
| 3518 | } | 3537 | } |
| 3519 | 3538 | ||
| 3520 | // Depth prompt (character-specific A/N) | 3539 | // Depth prompt (character-specific A/N) |
| @@ -3767,7 +3786,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3767 | personality: personality, | 3786 | personality: personality, |
| 3768 | persona: power_user.persona_description_position == persona_description_positions.IN_PROMPT ? persona : '', | 3787 | persona: power_user.persona_description_position == persona_description_positions.IN_PROMPT ? persona : '', |
| 3769 | scenario: scenario, | 3788 | scenario: scenario, |
| 3770 | system: isInstruct ? system : '', | 3789 | system: system, |
| 3771 | char: name2, | 3790 | char: name2, |
| 3772 | user: name1, | 3791 | user: name1, |
| 3773 | wiBefore: worldInfoBefore, | 3792 | wiBefore: worldInfoBefore, |
| @@ -4340,7 +4359,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4340 | this_max_context: this_max_context, | 4359 | this_max_context: this_max_context, |
| 4341 | padding: power_user.token_padding, | 4360 | padding: power_user.token_padding, |
| 4342 | main_api: main_api, | 4361 | main_api: main_api, |
| 4343 | instruction: isInstruct ? substituteParams(power_user.prefer_character_prompt && system ? system : power_user.instruct.system_prompt) : '', | 4362 | instruction: main_api !== 'openai' && power_user.sysprompt.enabled ? substituteParams(power_user.prefer_character_prompt && system ? system : power_user.sysprompt.content) : '', |
| 4344 | userPersona: (power_user.persona_description_position == persona_description_positions.IN_PROMPT ? (persona || '') : ''), | 4363 | userPersona: (power_user.persona_description_position == persona_description_positions.IN_PROMPT ? (persona || '') : ''), |
| 4345 | tokenizer: getFriendlyTokenizerName(main_api).tokenizerName || '', | 4364 | tokenizer: getFriendlyTokenizerName(main_api).tokenizerName || '', |
| 4346 | }; | 4365 | }; |
| @@ -4839,6 +4858,13 @@ export function getMaxContextSize(overrideResponseLength = null) { | |||
| 4839 | console.log(`NovelAI subscription limit reached. Max context size is now ${this_max_context}`); | 4858 | console.log(`NovelAI subscription limit reached. Max context size is now ${this_max_context}`); |
| 4840 | } | 4859 | } |
| 4841 | } | 4860 | } |
| 4861 | if (nai_settings.model_novel.includes('erato')) { | ||
| 4862 | // subscriber limits coming soon | ||
| 4863 | this_max_context = Math.min(max_context, 8192); | ||
| 4864 | |||
| 4865 | // Added special tokens and whatnot | ||
| 4866 | this_max_context -= 1; | ||
| 4867 | } | ||
| 4842 | 4868 | ||
| 4843 | this_max_context = this_max_context - (overrideResponseLength || amount_gen); | 4869 | this_max_context = this_max_context - (overrideResponseLength || amount_gen); |
| 4844 | } | 4870 | } |
| @@ -5466,7 +5492,7 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc | |||
| 5466 | } | 5492 | } |
| 5467 | 5493 | ||
| 5468 | if (!displayIncompleteSentences && power_user.trim_sentences) { | 5494 | if (!displayIncompleteSentences && power_user.trim_sentences) { |
| 5469 | getMessage = trimToEndSentence(getMessage, power_user.include_newline); | 5495 | getMessage = trimToEndSentence(getMessage); |
| 5470 | } | 5496 | } |
| 5471 | 5497 | ||
| 5472 | if (power_user.trim_spaces) { | 5498 | if (power_user.trim_spaces) { |
| @@ -5698,10 +5724,10 @@ export function deactivateSendButtons() { | |||
| 5698 | } | 5724 | } |
| 5699 | 5725 | ||
| 5700 | export function resetChatState() { | 5726 | export function resetChatState() { |
| 5727 | // replaces deleted charcter name with system user since it will be displayed next. | ||
| 5728 | name2 = (this_chid === undefined && neutralCharacterName) ? neutralCharacterName : systemUserName; | ||
| 5701 | //unsets expected chid before reloading (related to getCharacters/printCharacters from using old arrays) | 5729 | //unsets expected chid before reloading (related to getCharacters/printCharacters from using old arrays) |
| 5702 | this_chid = undefined; | 5730 | this_chid = undefined; |
| 5703 | // replaces deleted charcter name with system user since it will be displayed next. | ||
| 5704 | name2 = systemUserName; | ||
| 5705 | // sets up system user to tell user about having deleted a character | 5731 | // sets up system user to tell user about having deleted a character |
| 5706 | chat.splice(0, chat.length, ...SAFETY_CHAT); | 5732 | chat.splice(0, chat.length, ...SAFETY_CHAT); |
| 5707 | // resets chat metadata | 5733 | // resets chat metadata |
| @@ -6917,15 +6943,13 @@ export async function displayPastChats() { | |||
| 6917 | } | 6943 | } |
| 6918 | // Check whether `text` {string} includes all of the `fragments` {string[]}. | 6944 | // Check whether `text` {string} includes all of the `fragments` {string[]}. |
| 6919 | function matchFragments(fragments, text) { | 6945 | function matchFragments(fragments, text) { |
| 6920 | if (!text) { | 6946 | if (!text || !text.toLowerCase) return false; |
| 6921 | return false; | 6947 | return fragments.every(item => text.toLowerCase().includes(item)); |
| 6922 | } | ||
| 6923 | return fragments.every(item => text.includes(item)); | ||
| 6924 | } | 6948 | } |
| 6925 | const fragments = makeQueryFragments(searchQuery); | 6949 | const fragments = makeQueryFragments(searchQuery); |
| 6926 | // At least one chat message must match *all* the fragments. | 6950 | // At least one chat message must match *all* the fragments. |
| 6927 | // Currently, this doesn't match if the fragment matches are distributed across several chat messages. | 6951 | // Currently, this doesn't match if the fragment matches are distributed across several chat messages. |
| 6928 | return chatContent && Object.values(chatContent).some(message => matchFragments(fragments, message?.mes?.toLowerCase())); | 6952 | return chatContent && Object.values(chatContent).some(message => matchFragments(fragments, message?.mes)); |
| 6929 | }); | 6953 | }); |
| 6930 | 6954 | ||
| 6931 | console.debug(filteredData); | 6955 | console.debug(filteredData); |
| @@ -8565,20 +8589,27 @@ async function connectAPISlash(args, text) { | |||
| 8565 | return ''; | 8589 | return ''; |
| 8566 | } | 8590 | } |
| 8567 | 8591 | ||
| 8568 | $(`#main_api option[value='${apiConfig.selected || text}']`).prop('selected', true); | 8592 | let connectionRequired = false; |
| 8569 | $('#main_api').trigger('change'); | ||
| 8570 | 8593 | ||
| 8571 | if (apiConfig.source) { | 8594 | if (main_api !== apiConfig.selected) { |
| 8595 | $(`#main_api option[value='${apiConfig.selected || text}']`).prop('selected', true); | ||
| 8596 | $('#main_api').trigger('change'); | ||
| 8597 | connectionRequired = true; | ||
| 8598 | } | ||
| 8599 | |||
| 8600 | if (apiConfig.source && oai_settings.chat_completion_source !== apiConfig.source) { | ||
| 8572 | $(`#chat_completion_source option[value='${apiConfig.source}']`).prop('selected', true); | 8601 | $(`#chat_completion_source option[value='${apiConfig.source}']`).prop('selected', true); |
| 8573 | $('#chat_completion_source').trigger('change'); | 8602 | $('#chat_completion_source').trigger('change'); |
| 8603 | connectionRequired = true; | ||
| 8574 | } | 8604 | } |
| 8575 | 8605 | ||
| 8576 | if (apiConfig.type) { | 8606 | if (apiConfig.type && textgen_settings.type !== apiConfig.type) { |
| 8577 | $(`#textgen_type option[value='${apiConfig.type}']`).prop('selected', true); | 8607 | $(`#textgen_type option[value='${apiConfig.type}']`).prop('selected', true); |
| 8578 | $('#textgen_type').trigger('change'); | 8608 | $('#textgen_type').trigger('change'); |
| 8609 | connectionRequired = true; | ||
| 8579 | } | 8610 | } |
| 8580 | 8611 | ||
| 8581 | if (apiConfig.button) { | 8612 | if (connectionRequired && apiConfig.button) { |
| 8582 | $(apiConfig.button).trigger('click'); | 8613 | $(apiConfig.button).trigger('click'); |
| 8583 | } | 8614 | } |
| 8584 | 8615 | ||
| @@ -8803,7 +8834,7 @@ export async function renameChat(oldFileName, newName) { | |||
| 8803 | is_group: !!selected_group, | 8834 | is_group: !!selected_group, |
| 8804 | avatar_url: characters[this_chid]?.avatar, | 8835 | avatar_url: characters[this_chid]?.avatar, |
| 8805 | original_file: `${oldFileName}.jsonl`, | 8836 | original_file: `${oldFileName}.jsonl`, |
| 8806 | renamed_file: `${newName}.jsonl`, | 8837 | renamed_file: `${newName.trim()}.jsonl`, |
| 8807 | }; | 8838 | }; |
| 8808 | 8839 | ||
| 8809 | try { | 8840 | try { |
| @@ -8824,6 +8855,10 @@ export async function renameChat(oldFileName, newName) { | |||
| 8824 | throw new Error('Server returned an error.'); | 8855 | throw new Error('Server returned an error.'); |
| 8825 | } | 8856 | } |
| 8826 | 8857 | ||
| 8858 | if (data.sanitizedFileName) { | ||
| 8859 | newName = data.sanitizedFileName; | ||
| 8860 | } | ||
| 8861 | |||
| 8827 | if (selected_group) { | 8862 | if (selected_group) { |
| 8828 | await renameGroupChat(selected_group, oldFileName, newName); | 8863 | await renameGroupChat(selected_group, oldFileName, newName); |
| 8829 | } | 8864 | } |
| @@ -8945,15 +8980,12 @@ export async function deleteCharacter(characterKey, { deleteChats = true } = {}) | |||
| 8945 | * It also ensures to save the settings after all the operations. | 8980 | * It also ensures to save the settings after all the operations. |
| 8946 | */ | 8981 | */ |
| 8947 | async function removeCharacterFromUI() { | 8982 | async function removeCharacterFromUI() { |
| 8983 | preserveNeutralChat(); | ||
| 8948 | await clearChat(); | 8984 | await clearChat(); |
| 8949 | $('#character_cross').click(); | 8985 | $('#character_cross').trigger('click'); |
| 8950 | this_chid = undefined; | 8986 | resetChatState(); |
| 8951 | characters.length = 0; | ||
| 8952 | name2 = systemUserName; | ||
| 8953 | chat.splice(0, chat.length, ...SAFETY_CHAT); | ||
| 8954 | chat_metadata = {}; | ||
| 8955 | $(document.getElementById('rm_button_selected_ch')).children('h2').text(''); | 8987 | $(document.getElementById('rm_button_selected_ch')).children('h2').text(''); |
| 8956 | this_chid = undefined; | 8988 | restoreNeutralChat(); |
| 8957 | await getCharacters(); | 8989 | await getCharacters(); |
| 8958 | await printMessages(); | 8990 | await printMessages(); |
| 8959 | saveSettingsDebounced(); | 8991 | saveSettingsDebounced(); |
| @@ -1,12 +1,13 @@ | |||
| 1 | 'use strict'; | 1 | 'use strict'; |
| 2 | 2 | ||
| 3 | import { callPopup, event_types, eventSource, is_send_press, main_api, substituteParams } from '../script.js'; | 3 | import { event_types, eventSource, is_send_press, main_api, substituteParams } from '../script.js'; |
| 4 | import { is_group_generating } from './group-chats.js'; | 4 | import { is_group_generating } from './group-chats.js'; |
| 5 | import { Message, TokenHandler } from './openai.js'; | 5 | import { Message, TokenHandler } from './openai.js'; |
| 6 | import { power_user } from './power-user.js'; | 6 | import { power_user } from './power-user.js'; |
| 7 | import { debounce, waitUntilCondition, escapeHtml } from './utils.js'; | 7 | import { debounce, waitUntilCondition, escapeHtml } from './utils.js'; |
| 8 | import { debounce_timeout } from './constants.js'; | 8 | import { debounce_timeout } from './constants.js'; |
| 9 | import { renderTemplateAsync } from './templates.js'; | 9 | import { renderTemplateAsync } from './templates.js'; |
| 10 | import { Popup } from './popup.js'; | ||
| 10 | 11 | ||
| 11 | function debouncePromise(func, delay) { | 12 | function debouncePromise(func, delay) { |
| 12 | let timeoutId; | 13 | let timeoutId; |
| @@ -427,12 +428,13 @@ class PromptManager { | |||
| 427 | 428 | ||
| 428 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name').value = prompt.name; | 429 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name').value = prompt.name; |
| 429 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role').value = 'system'; | 430 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role').value = 'system'; |
| 430 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').value = prompt.content; | 431 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').value = prompt.content ?? ''; |
| 431 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').value = prompt.injection_position ?? 0; | 432 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').value = prompt.injection_position ?? 0; |
| 432 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth').value = prompt.injection_depth ?? DEFAULT_DEPTH; | 433 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth').value = prompt.injection_depth ?? DEFAULT_DEPTH; |
| 433 | document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block').style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; | 434 | document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block').style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; |
| 434 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides').checked = prompt.forbid_overrides ?? false; | 435 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides').checked = prompt.forbid_overrides ?? false; |
| 435 | document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block').style.visibility = this.overridablePrompts.includes(prompt.identifier) ? 'visible' : 'hidden'; | 436 | document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block').style.visibility = this.overridablePrompts.includes(prompt.identifier) ? 'visible' : 'hidden'; |
| 437 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').disabled = prompt.marker ?? false; | ||
| 436 | 438 | ||
| 437 | if (!this.systemPrompts.includes(promptId)) { | 439 | if (!this.systemPrompts.includes(promptId)) { |
| 438 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').removeAttribute('disabled'); | 440 | document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').removeAttribute('disabled'); |
| @@ -452,21 +454,24 @@ class PromptManager { | |||
| 452 | }; | 454 | }; |
| 453 | 455 | ||
| 454 | // Delete selected prompt from list form and close edit form | 456 | // Delete selected prompt from list form and close edit form |
| 455 | this.handleDeletePrompt = (event) => { | 457 | this.handleDeletePrompt = async (event) => { |
| 456 | const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value; | 458 | Popup.show.confirm('Are you sure you want to delete this prompt?', null).then((userChoice) => { |
| 457 | const prompt = this.getPromptById(promptID); | 459 | if (!userChoice) return; |
| 460 | const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value; | ||
| 461 | const prompt = this.getPromptById(promptID); | ||
| 458 | 462 | ||
| 459 | if (prompt && true === this.isPromptDeletionAllowed(prompt)) { | 463 | if (prompt && true === this.isPromptDeletionAllowed(prompt)) { |
| 460 | const promptIndex = this.getPromptIndexById(promptID); | 464 | const promptIndex = this.getPromptIndexById(promptID); |
| 461 | this.serviceSettings.prompts.splice(Number(promptIndex), 1); | 465 | this.serviceSettings.prompts.splice(Number(promptIndex), 1); |
| 462 | 466 | ||
| 463 | this.log('Deleted prompt: ' + prompt.identifier); | 467 | this.log('Deleted prompt: ' + prompt.identifier); |
| 464 | 468 | ||
| 465 | this.hidePopup(); | 469 | this.hidePopup(); |
| 466 | this.clearEditForm(); | 470 | this.clearEditForm(); |
| 467 | this.render(); | 471 | this.render(); |
| 468 | this.saveServiceSettings(); | 472 | this.saveServiceSettings(); |
| 469 | } | 473 | } |
| 474 | }); | ||
| 470 | }; | 475 | }; |
| 471 | 476 | ||
| 472 | // Create new prompt, then save it to settings and close form. | 477 | // Create new prompt, then save it to settings and close form. |
| @@ -526,9 +531,9 @@ class PromptManager { | |||
| 526 | 531 | ||
| 527 | // Import prompts for the selected character | 532 | // Import prompts for the selected character |
| 528 | this.handleImport = () => { | 533 | this.handleImport = () => { |
| 529 | callPopup('Existing prompts with the same ID will be overridden. Do you want to proceed?', 'confirm') | 534 | Popup.show.confirm('Existing prompts with the same ID will be overridden. Do you want to proceed?', null) |
| 530 | .then(userChoice => { | 535 | .then(userChoice => { |
| 531 | if (false === userChoice) return; | 536 | if (!userChoice) return; |
| 532 | 537 | ||
| 533 | const fileOpener = document.createElement('input'); | 538 | const fileOpener = document.createElement('input'); |
| 534 | fileOpener.type = 'file'; | 539 | fileOpener.type = 'file'; |
| @@ -562,9 +567,9 @@ class PromptManager { | |||
| 562 | 567 | ||
| 563 | // Restore default state of a characters prompt order | 568 | // Restore default state of a characters prompt order |
| 564 | this.handleCharacterReset = () => { | 569 | this.handleCharacterReset = () => { |
| 565 | callPopup('This will reset the prompt order for this character. You will not lose any prompts.', 'confirm') | 570 | Popup.show.confirm('This will reset the prompt order for this character. You will not lose any prompts.', null) |
| 566 | .then(userChoice => { | 571 | .then(userChoice => { |
| 567 | if (false === userChoice) return; | 572 | if (!userChoice) return; |
| 568 | 573 | ||
| 569 | this.removePromptOrderForCharacter(this.activeCharacter); | 574 | this.removePromptOrderForCharacter(this.activeCharacter); |
| 570 | this.addPromptOrderForCharacter(this.activeCharacter, promptManagerDefaultPromptOrder); | 575 | this.addPromptOrderForCharacter(this.activeCharacter, promptManagerDefaultPromptOrder); |
| @@ -920,7 +925,15 @@ class PromptManager { | |||
| 920 | * @returns {boolean} True if the prompt can be edited, false otherwise. | 925 | * @returns {boolean} True if the prompt can be edited, false otherwise. |
| 921 | */ | 926 | */ |
| 922 | isPromptEditAllowed(prompt) { | 927 | isPromptEditAllowed(prompt) { |
| 923 | return !prompt.marker; | 928 | const forceEditPrompts = [ |
| 929 | 'charDescription', | ||
| 930 | 'charPersonality', | ||
| 931 | 'scenario', | ||
| 932 | 'personaDescription', | ||
| 933 | 'worldInfoBefore', | ||
| 934 | 'worldInfoAfter', | ||
| 935 | ]; | ||
| 936 | return forceEditPrompts.includes(prompt.identifier) || !prompt.marker; | ||
| 924 | } | 937 | } |
| 925 | 938 | ||
| 926 | /** | 939 | /** |
| @@ -929,7 +942,17 @@ class PromptManager { | |||
| 929 | * @returns {boolean} True if the prompt can be deleted, false otherwise. | 942 | * @returns {boolean} True if the prompt can be deleted, false otherwise. |
| 930 | */ | 943 | */ |
| 931 | isPromptToggleAllowed(prompt) { | 944 | isPromptToggleAllowed(prompt) { |
| 932 | const forceTogglePrompts = ['charDescription', 'charPersonality', 'scenario', 'personaDescription', 'worldInfoBefore', 'worldInfoAfter', 'main', 'chatHistory', 'dialogueExamples']; | 945 | const forceTogglePrompts = [ |
| 946 | 'charDescription', | ||
| 947 | 'charPersonality', | ||
| 948 | 'scenario', | ||
| 949 | 'personaDescription', | ||
| 950 | 'worldInfoBefore', | ||
| 951 | 'worldInfoAfter', | ||
| 952 | 'main', | ||
| 953 | 'chatHistory', | ||
| 954 | 'dialogueExamples', | ||
| 955 | ]; | ||
| 933 | return prompt.marker && !forceTogglePrompts.includes(prompt.identifier) ? false : !this.configuration.toggleDisabled.includes(prompt.identifier); | 956 | return prompt.marker && !forceTogglePrompts.includes(prompt.identifier) ? false : !this.configuration.toggleDisabled.includes(prompt.identifier); |
| 934 | } | 957 | } |
| 935 | 958 | ||
| @@ -1182,8 +1205,9 @@ class PromptManager { | |||
| 1182 | const forbidOverridesBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block'); | 1205 | const forbidOverridesBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block'); |
| 1183 | 1206 | ||
| 1184 | nameField.value = prompt.name ?? ''; | 1207 | nameField.value = prompt.name ?? ''; |
| 1185 | roleField.value = prompt.role ?? ''; | 1208 | roleField.value = prompt.role ?? 'system'; |
| 1186 | promptField.value = prompt.content ?? ''; | 1209 | promptField.value = prompt.content ?? ''; |
| 1210 | promptField.disabled = prompt.marker ?? false; | ||
| 1187 | injectionPositionField.value = prompt.injection_position ?? INJECTION_POSITION.RELATIVE; | 1211 | injectionPositionField.value = prompt.injection_position ?? INJECTION_POSITION.RELATIVE; |
| 1188 | injectionDepthField.value = prompt.injection_depth ?? DEFAULT_DEPTH; | 1212 | injectionDepthField.value = prompt.injection_depth ?? DEFAULT_DEPTH; |
| 1189 | injectionDepthBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; | 1213 | injectionDepthBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; |
| @@ -1279,6 +1303,7 @@ class PromptManager { | |||
| 1279 | nameField.value = ''; | 1303 | nameField.value = ''; |
| 1280 | roleField.selectedIndex = 0; | 1304 | roleField.selectedIndex = 0; |
| 1281 | promptField.value = ''; | 1305 | promptField.value = ''; |
| 1306 | promptField.disabled = false; | ||
| 1282 | injectionPositionField.selectedIndex = 0; | 1307 | injectionPositionField.selectedIndex = 0; |
| 1283 | injectionPositionField.removeAttribute('disabled'); | 1308 | injectionPositionField.removeAttribute('disabled'); |
| 1284 | injectionDepthField.value = DEFAULT_DEPTH; | 1309 | injectionDepthField.value = DEFAULT_DEPTH; |
| @@ -1515,16 +1540,17 @@ class PromptManager { | |||
| 1515 | } | 1540 | } |
| 1516 | 1541 | ||
| 1517 | const encodedName = escapeHtml(prompt.name); | 1542 | const encodedName = escapeHtml(prompt.name); |
| 1543 | const isMarkerPrompt = prompt.marker && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE; | ||
| 1518 | const isSystemPrompt = !prompt.marker && prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE && !prompt.forbid_overrides; | 1544 | const isSystemPrompt = !prompt.marker && prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE && !prompt.forbid_overrides; |
| 1519 | const isImportantPrompt = !prompt.marker && prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE && prompt.forbid_overrides; | 1545 | const isImportantPrompt = !prompt.marker && prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE && prompt.forbid_overrides; |
| 1520 | const isUserPrompt = !prompt.marker && !prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE; | 1546 | const isUserPrompt = !prompt.marker && !prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE; |
| 1521 | const isInjectionPrompt = !prompt.marker && prompt.injection_position === INJECTION_POSITION.ABSOLUTE; | 1547 | const isInjectionPrompt = prompt.injection_position === INJECTION_POSITION.ABSOLUTE; |
| 1522 | const isOverriddenPrompt = Array.isArray(this.overriddenPrompts) && this.overriddenPrompts.includes(prompt.identifier); | 1548 | const isOverriddenPrompt = Array.isArray(this.overriddenPrompts) && this.overriddenPrompts.includes(prompt.identifier); |
| 1523 | const importantClass = isImportantPrompt ? `${prefix}prompt_manager_important` : ''; | 1549 | const importantClass = isImportantPrompt ? `${prefix}prompt_manager_important` : ''; |
| 1524 | listItemHtml += ` | 1550 | listItemHtml += ` |
| 1525 | <li class="${prefix}prompt_manager_prompt ${draggableClass} ${enabledClass} ${markerClass} ${importantClass}" data-pm-identifier="${prompt.identifier}"> | 1551 | <li class="${prefix}prompt_manager_prompt ${draggableClass} ${enabledClass} ${markerClass} ${importantClass}" data-pm-identifier="${prompt.identifier}"> |
| 1526 | <span class="${prefix}prompt_manager_prompt_name" data-pm-name="${encodedName}"> | 1552 | <span class="${prefix}prompt_manager_prompt_name" data-pm-name="${encodedName}"> |
| 1527 | ${prompt.marker ? '<span class="fa-fw fa-solid fa-thumb-tack" title="Marker"></span>' : ''} | 1553 | ${isMarkerPrompt ? '<span class="fa-fw fa-solid fa-thumb-tack" title="Marker"></span>' : ''} |
| 1528 | ${isSystemPrompt ? '<span class="fa-fw fa-solid fa-square-poll-horizontal" title="Global Prompt"></span>' : ''} | 1554 | ${isSystemPrompt ? '<span class="fa-fw fa-solid fa-square-poll-horizontal" title="Global Prompt"></span>' : ''} |
| 1529 | ${isImportantPrompt ? '<span class="fa-fw fa-solid fa-star" title="Important Prompt"></span>' : ''} | 1555 | ${isImportantPrompt ? '<span class="fa-fw fa-solid fa-star" title="Important Prompt"></span>' : ''} |
| 1530 | ${isUserPrompt ? '<span class="fa-fw fa-solid fa-user" title="User Prompt"></span>' : ''} | 1556 | ${isUserPrompt ? '<span class="fa-fw fa-solid fa-user" title="User Prompt"></span>' : ''} |
| @@ -1724,7 +1750,7 @@ class PromptManager { | |||
| 1724 | */ | 1750 | */ |
| 1725 | showPopup(area = 'edit') { | 1751 | showPopup(area = 'edit') { |
| 1726 | const areaElement = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_' + area); | 1752 | const areaElement = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_' + area); |
| 1727 | areaElement.style.display = 'block'; | 1753 | areaElement.style.display = 'flex'; |
| 1728 | 1754 | ||
| 1729 | $('#' + this.configuration.prefix + 'prompt_manager_popup').first() | 1755 | $('#' + this.configuration.prefix + 'prompt_manager_popup').first() |
| 1730 | .slideDown(200, 'swing') | 1756 | .slideDown(200, 'swing') |
| @@ -737,6 +737,16 @@ export function initRossMods() { | |||
| 737 | RA_autoconnect(); | 737 | RA_autoconnect(); |
| 738 | } | 738 | } |
| 739 | 739 | ||
| 740 | if (isMobile()) { | ||
| 741 | const fixFunkyPositioning = () => { | ||
| 742 | console.debug('[Mobile] Device viewport change detected.'); | ||
| 743 | document.documentElement.style.position = 'fixed'; | ||
| 744 | requestAnimationFrame(() => document.documentElement.style.position = ''); | ||
| 745 | }; | ||
| 746 | window.addEventListener('resize', fixFunkyPositioning); | ||
| 747 | window.addEventListener('orientationchange', fixFunkyPositioning); | ||
| 748 | } | ||
| 749 | |||
| 740 | $('#main_api').change(function () { | 750 | $('#main_api').change(function () { |
| 741 | var PrevAPI = main_api; | 751 | var PrevAPI = main_api; |
| 742 | setTimeout(() => RA_autoconnect(PrevAPI), 100); | 752 | setTimeout(() => RA_autoconnect(PrevAPI), 100); |
| @@ -313,7 +313,7 @@ async function onDeleteBackgroundClick(e) { | |||
| 313 | } | 313 | } |
| 314 | } | 314 | } |
| 315 | 315 | ||
| 316 | const autoBgPrompt = 'Pause your roleplay and choose a location ONLY from the provided list that is the most suitable for the current scene. Do not output any other text:\n{0}'; | 316 | const autoBgPrompt = 'Ignore previous instructions and choose a location ONLY from the provided list that is the most suitable for the current scene. Do not output any other text:\n{0}'; |
| 317 | 317 | ||
| 318 | async function autoBackgroundCommand() { | 318 | async function autoBackgroundCommand() { |
| 319 | /** @type {HTMLElement[]} */ | 319 | /** @type {HTMLElement[]} */ |
| @@ -19,6 +19,8 @@ import { | |||
| 19 | this_chid, | 19 | this_chid, |
| 20 | saveChatConditional, | 20 | saveChatConditional, |
| 21 | chat_metadata, | 21 | chat_metadata, |
| 22 | neutralCharacterName, | ||
| 23 | updateChatMetadata, | ||
| 22 | } from '../script.js'; | 24 | } from '../script.js'; |
| 23 | import { selected_group } from './group-chats.js'; | 25 | import { selected_group } from './group-chats.js'; |
| 24 | import { power_user } from './power-user.js'; | 26 | import { power_user } from './power-user.js'; |
| @@ -133,10 +135,11 @@ export async function hideChatMessageRange(start, end, unhide) { | |||
| 133 | const message = chat[messageId]; | 135 | const message = chat[messageId]; |
| 134 | if (!message) continue; | 136 | if (!message) continue; |
| 135 | 137 | ||
| 138 | message.is_system = hide; | ||
| 139 | |||
| 140 | // Also toggle "hidden" state for all visible messages | ||
| 136 | const messageBlock = $(`.mes[mesid="${messageId}"]`); | 141 | const messageBlock = $(`.mes[mesid="${messageId}"]`); |
| 137 | if (!messageBlock.length) continue; | 142 | if (!messageBlock.length) continue; |
| 138 | |||
| 139 | message.is_system = hide; | ||
| 140 | messageBlock.attr('is_system', String(hide)); | 143 | messageBlock.attr('is_system', String(hide)); |
| 141 | } | 144 | } |
| 142 | 145 | ||
| @@ -1352,6 +1355,32 @@ async function verifyAttachmentsForSource(source) { | |||
| 1352 | } | 1355 | } |
| 1353 | } | 1356 | } |
| 1354 | 1357 | ||
| 1358 | const NEUTRAL_CHAT_KEY = 'neutralChat'; | ||
| 1359 | |||
| 1360 | export function preserveNeutralChat() { | ||
| 1361 | if (this_chid !== undefined || selected_group || name2 !== neutralCharacterName) { | ||
| 1362 | return; | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | sessionStorage.setItem(NEUTRAL_CHAT_KEY, JSON.stringify({ chat, chat_metadata })); | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | export function restoreNeutralChat() { | ||
| 1369 | if (this_chid !== undefined || selected_group || name2 !== neutralCharacterName) { | ||
| 1370 | return; | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | const neutralChat = sessionStorage.getItem(NEUTRAL_CHAT_KEY); | ||
| 1374 | if (!neutralChat) { | ||
| 1375 | return; | ||
| 1376 | } | ||
| 1377 | |||
| 1378 | const { chat: neutralChatData, chat_metadata: neutralChatMetadata } = JSON.parse(neutralChat); | ||
| 1379 | chat.splice(0, chat.length, ...neutralChatData); | ||
| 1380 | updateChatMetadata(neutralChatMetadata, true); | ||
| 1381 | sessionStorage.removeItem(NEUTRAL_CHAT_KEY); | ||
| 1382 | } | ||
| 1383 | |||
| 1355 | /** | 1384 | /** |
| 1356 | * Registers a file converter function. | 1385 | * Registers a file converter function. |
| 1357 | * @param {string} mimeType MIME type | 1386 | * @param {string} mimeType MIME type |
| @@ -29,7 +29,6 @@ export function saveMetadataDebounced() { | |||
| 29 | const characterId = context.characterId; | 29 | const characterId = context.characterId; |
| 30 | 30 | ||
| 31 | if (saveMetadataTimeout) { | 31 | if (saveMetadataTimeout) { |
| 32 | console.debug('Clearing save metadata timeout'); | ||
| 33 | clearTimeout(saveMetadataTimeout); | 32 | clearTimeout(saveMetadataTimeout); |
| 34 | } | 33 | } |
| 35 | 34 | ||
| @@ -1,6 +1,6 @@ | |||
| 1 | import { ensureImageFormatSupported, getBase64Async, isTrueBoolean, saveBase64AsFile } from '../../utils.js'; | 1 | import { ensureImageFormatSupported, getBase64Async, isTrueBoolean, saveBase64AsFile } from '../../utils.js'; |
| 2 | import { getContext, getApiUrl, doExtrasFetch, extension_settings, modules, renderExtensionTemplateAsync } from '../../extensions.js'; | 2 | import { getContext, getApiUrl, doExtrasFetch, extension_settings, modules, renderExtensionTemplateAsync } from '../../extensions.js'; |
| 3 | import { appendMediaToMessage, callPopup, eventSource, event_types, getRequestHeaders, saveChatConditional, saveSettingsDebounced, substituteParamsExtended } from '../../../script.js'; | 3 | import { appendMediaToMessage, callPopup, eventSource, event_types, getRequestHeaders, main_api, saveChatConditional, saveSettingsDebounced, substituteParamsExtended } from '../../../script.js'; |
| 4 | import { getMessageTimeStamp } from '../../RossAscends-mods.js'; | 4 | import { getMessageTimeStamp } from '../../RossAscends-mods.js'; |
| 5 | import { SECRET_KEYS, secret_state } from '../../secrets.js'; | 5 | import { SECRET_KEYS, secret_state } from '../../secrets.js'; |
| 6 | import { getMultimodalCaption } from '../shared.js'; | 6 | import { getMultimodalCaption } from '../shared.js'; |
| @@ -403,6 +403,7 @@ jQuery(async function () { | |||
| 403 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openai' && (secret_state[SECRET_KEYS.OPENAI] || extension_settings.caption.allow_reverse_proxy)) || | 403 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openai' && (secret_state[SECRET_KEYS.OPENAI] || extension_settings.caption.allow_reverse_proxy)) || |
| 404 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openrouter' && secret_state[SECRET_KEYS.OPENROUTER]) || | 404 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openrouter' && secret_state[SECRET_KEYS.OPENROUTER]) || |
| 405 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'zerooneai' && secret_state[SECRET_KEYS.ZEROONEAI]) || | 405 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'zerooneai' && secret_state[SECRET_KEYS.ZEROONEAI]) || |
| 406 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'mistral' && (secret_state[SECRET_KEYS.MISTRALAI] || extension_settings.caption.allow_reverse_proxy)) || | ||
| 406 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'google' && (secret_state[SECRET_KEYS.MAKERSUITE] || extension_settings.caption.allow_reverse_proxy)) || | 407 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'google' && (secret_state[SECRET_KEYS.MAKERSUITE] || extension_settings.caption.allow_reverse_proxy)) || |
| 407 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'anthropic' && (secret_state[SECRET_KEYS.CLAUDE] || extension_settings.caption.allow_reverse_proxy)) || | 408 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'anthropic' && (secret_state[SECRET_KEYS.CLAUDE] || extension_settings.caption.allow_reverse_proxy)) || |
| 408 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'ollama' && textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]) || | 409 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'ollama' && textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]) || |
| @@ -431,14 +432,9 @@ jQuery(async function () { | |||
| 431 | $('#form_sheld').append(imgForm); | 432 | $('#form_sheld').append(imgForm); |
| 432 | $('#img_file').on('change', (e) => onSelectImage(e.originalEvent, '', false)); | 433 | $('#img_file').on('change', (e) => onSelectImage(e.originalEvent, '', false)); |
| 433 | } | 434 | } |
| 434 | function switchMultimodalBlocks() { | 435 | async function switchMultimodalBlocks() { |
| 436 | await addOpenRouterModels(); | ||
| 435 | const isMultimodal = extension_settings.caption.source === 'multimodal'; | 437 | const isMultimodal = extension_settings.caption.source === 'multimodal'; |
| 436 | $('#caption_ollama_pull').on('click', (e) => { | ||
| 437 | const presetModel = extension_settings.caption.multimodal_model !== 'ollama_current' ? extension_settings.caption.multimodal_model : ''; | ||
| 438 | e.preventDefault(); | ||
| 439 | $('#ollama_download_model').trigger('click'); | ||
| 440 | $('#dialogue_popup_input').val(presetModel); | ||
| 441 | }); | ||
| 442 | $('#caption_multimodal_block').toggle(isMultimodal); | 438 | $('#caption_multimodal_block').toggle(isMultimodal); |
| 443 | $('#caption_prompt_block').toggle(isMultimodal); | 439 | $('#caption_prompt_block').toggle(isMultimodal); |
| 444 | $('#caption_multimodal_api').val(extension_settings.caption.multimodal_api); | 440 | $('#caption_multimodal_api').val(extension_settings.caption.multimodal_api); |
| @@ -448,30 +444,48 @@ jQuery(async function () { | |||
| 448 | const types = type.split(','); | 444 | const types = type.split(','); |
| 449 | $(this).toggle(types.includes(extension_settings.caption.multimodal_api)); | 445 | $(this).toggle(types.includes(extension_settings.caption.multimodal_api)); |
| 450 | }); | 446 | }); |
| 451 | $('#caption_multimodal_api').on('change', () => { | ||
| 452 | const api = String($('#caption_multimodal_api').val()); | ||
| 453 | const model = String($(`#caption_multimodal_model option[data-type="${api}"]`).first().val()); | ||
| 454 | extension_settings.caption.multimodal_api = api; | ||
| 455 | extension_settings.caption.multimodal_model = model; | ||
| 456 | saveSettingsDebounced(); | ||
| 457 | switchMultimodalBlocks(); | ||
| 458 | }); | ||
| 459 | $('#caption_multimodal_model').on('change', () => { | ||
| 460 | extension_settings.caption.multimodal_model = String($('#caption_multimodal_model').val()); | ||
| 461 | saveSettingsDebounced(); | ||
| 462 | }); | ||
| 463 | } | 447 | } |
| 464 | async function addSettings() { | 448 | async function addSettings() { |
| 465 | const html = await renderExtensionTemplateAsync('caption', 'settings', { TEMPLATE_DEFAULT, PROMPT_DEFAULT }); | 449 | const html = await renderExtensionTemplateAsync('caption', 'settings', { TEMPLATE_DEFAULT, PROMPT_DEFAULT }); |
| 466 | $('#caption_container').append(html); | 450 | $('#caption_container').append(html); |
| 467 | } | 451 | } |
| 452 | async function addOpenRouterModels() { | ||
| 453 | const dropdown = document.getElementById('caption_multimodal_model'); | ||
| 454 | if (!(dropdown instanceof HTMLSelectElement)) { | ||
| 455 | return; | ||
| 456 | } | ||
| 457 | if (extension_settings.caption.source !== 'multimodal' || extension_settings.caption.multimodal_api !== 'openrouter') { | ||
| 458 | return; | ||
| 459 | } | ||
| 460 | const options = Array.from(dropdown.options); | ||
| 461 | const response = await fetch('/api/openrouter/models/multimodal', { | ||
| 462 | method: 'POST', | ||
| 463 | headers: getRequestHeaders(), | ||
| 464 | }); | ||
| 465 | if (!response.ok) { | ||
| 466 | return; | ||
| 467 | } | ||
| 468 | const modelIds = await response.json(); | ||
| 469 | if (Array.isArray(modelIds) && modelIds.length > 0) { | ||
| 470 | modelIds.forEach((modelId) => { | ||
| 471 | if (!modelId || typeof modelId !== 'string' || options.some(o => o.value === modelId)) { | ||
| 472 | return; | ||
| 473 | } | ||
| 474 | const option = document.createElement('option'); | ||
| 475 | option.value = modelId; | ||
| 476 | option.textContent = modelId; | ||
| 477 | option.dataset.type = 'openrouter'; | ||
| 478 | dropdown.add(option); | ||
| 479 | }); | ||
| 480 | } | ||
| 481 | } | ||
| 468 | 482 | ||
| 469 | await addSettings(); | 483 | await addSettings(); |
| 470 | addPictureSendForm(); | 484 | addPictureSendForm(); |
| 471 | addSendPictureButton(); | 485 | addSendPictureButton(); |
| 472 | setImageIcon(); | 486 | setImageIcon(); |
| 473 | migrateSettings(); | 487 | migrateSettings(); |
| 474 | switchMultimodalBlocks(); | 488 | await switchMultimodalBlocks(); |
| 475 | 489 | ||
| 476 | $('#caption_refine_mode').prop('checked', !!(extension_settings.caption.refine_mode)); | 490 | $('#caption_refine_mode').prop('checked', !!(extension_settings.caption.refine_mode)); |
| 477 | $('#caption_allow_reverse_proxy').prop('checked', !!(extension_settings.caption.allow_reverse_proxy)); | 491 | $('#caption_allow_reverse_proxy').prop('checked', !!(extension_settings.caption.allow_reverse_proxy)); |
| @@ -506,6 +520,24 @@ jQuery(async function () { | |||
| 506 | extension_settings.caption.auto_mode = !!$('#caption_auto_mode').prop('checked'); | 520 | extension_settings.caption.auto_mode = !!$('#caption_auto_mode').prop('checked'); |
| 507 | saveSettingsDebounced(); | 521 | saveSettingsDebounced(); |
| 508 | }); | 522 | }); |
| 523 | $('#caption_ollama_pull').on('click', (e) => { | ||
| 524 | const presetModel = extension_settings.caption.multimodal_model !== 'ollama_current' ? extension_settings.caption.multimodal_model : ''; | ||
| 525 | e.preventDefault(); | ||
| 526 | $('#ollama_download_model').trigger('click'); | ||
| 527 | $('#dialogue_popup_input').val(presetModel); | ||
| 528 | }); | ||
| 529 | $('#caption_multimodal_api').on('change', () => { | ||
| 530 | const api = String($('#caption_multimodal_api').val()); | ||
| 531 | const model = String($(`#caption_multimodal_model option[data-type="${api}"]`).first().val()); | ||
| 532 | extension_settings.caption.multimodal_api = api; | ||
| 533 | extension_settings.caption.multimodal_model = model; | ||
| 534 | saveSettingsDebounced(); | ||
| 535 | switchMultimodalBlocks(); | ||
| 536 | }); | ||
| 537 | $('#caption_multimodal_model').on('change', () => { | ||
| 538 | extension_settings.caption.multimodal_model = String($('#caption_multimodal_model').val()); | ||
| 539 | saveSettingsDebounced(); | ||
| 540 | }); | ||
| 509 | 541 | ||
| 510 | const onMessageEvent = async (index) => { | 542 | const onMessageEvent = async (index) => { |
| 511 | if (!extension_settings.caption.auto_mode) { | 543 | if (!extension_settings.caption.auto_mode) { |
| @@ -531,14 +563,15 @@ jQuery(async function () { | |||
| 531 | await captionExistingMessage(data); | 563 | await captionExistingMessage(data); |
| 532 | appendMediaToMessage(data, messageBlock, false); | 564 | appendMediaToMessage(data, messageBlock, false); |
| 533 | await saveChatConditional(); | 565 | await saveChatConditional(); |
| 534 | } catch(e) { | 566 | } catch (e) { |
| 535 | console.error('Message image recaption failed', e); | 567 | console.error('Message image recaption failed', e); |
| 536 | } finally { | 568 | } finally { |
| 537 | messageImg.removeClass(animationClass); | 569 | messageImg.removeClass(animationClass); |
| 538 | } | 570 | } |
| 539 | }); | 571 | }); |
| 540 | 572 | ||
| 541 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'caption', | 573 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 574 | name: 'caption', | ||
| 542 | callback: captionCommandCallback, | 575 | callback: captionCommandCallback, |
| 543 | returns: 'caption', | 576 | returns: 'caption', |
| 544 | namedArgumentList: [ | 577 | namedArgumentList: [ |
| @@ -23,6 +23,7 @@ | |||
| 23 | <option value="google">Google AI Studio</option> | 23 | <option value="google">Google AI Studio</option> |
| 24 | <option value="koboldcpp">KoboldCpp</option> | 24 | <option value="koboldcpp">KoboldCpp</option> |
| 25 | <option value="llamacpp">llama.cpp</option> | 25 | <option value="llamacpp">llama.cpp</option> |
| 26 | <option value="mistral">MistralAI</option> | ||
| 26 | <option value="ollama">Ollama</option> | 27 | <option value="ollama">Ollama</option> |
| 27 | <option value="openai">OpenAI</option> | 28 | <option value="openai">OpenAI</option> |
| 28 | <option value="openrouter">OpenRouter</option> | 29 | <option value="openrouter">OpenRouter</option> |
| @@ -33,6 +34,8 @@ | |||
| 33 | <div class="flex1 flex-container flexFlowColumn flexNoGap"> | 34 | <div class="flex1 flex-container flexFlowColumn flexNoGap"> |
| 34 | <label for="caption_multimodal_model" data-i18n="Model">Model</label> | 35 | <label for="caption_multimodal_model" data-i18n="Model">Model</label> |
| 35 | <select id="caption_multimodal_model" class="flex1 text_pole"> | 36 | <select id="caption_multimodal_model" class="flex1 text_pole"> |
| 37 | <option data-type="mistral" value="pixtral-latest">pixtral-latest</option> | ||
| 38 | <option data-type="mistral" value="pixtral-12b-2409">pixtral-12b-2409</option> | ||
| 36 | <option data-type="zerooneai" value="yi-vision">yi-vision</option> | 39 | <option data-type="zerooneai" value="yi-vision">yi-vision</option> |
| 37 | <option data-type="openai" value="gpt-4-vision-preview">gpt-4-vision-preview</option> | 40 | <option data-type="openai" value="gpt-4-vision-preview">gpt-4-vision-preview</option> |
| 38 | <option data-type="openai" value="gpt-4-turbo">gpt-4-turbo</option> | 41 | <option data-type="openai" value="gpt-4-turbo">gpt-4-turbo</option> |
| @@ -96,7 +99,7 @@ | |||
| 96 | <div data-type="ollama"> | 99 | <div data-type="ollama"> |
| 97 | The model must be downloaded first! Do it with the <code>ollama pull</code> command or <a href="#" id="caption_ollama_pull">click here</a>. | 100 | The model must be downloaded first! Do it with the <code>ollama pull</code> command or <a href="#" id="caption_ollama_pull">click here</a>. |
| 98 | </div> | 101 | </div> |
| 99 | <label data-type="openai,anthropic,google" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid."> | 102 | <label data-type="openai,anthropic,google,mistral" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid."> |
| 100 | <input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox"> | 103 | <input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox"> |
| 101 | <span data-i18n="Allow reverse proxy">Allow reverse proxy</span> | 104 | <span data-i18n="Allow reverse proxy">Allow reverse proxy</span> |
| 102 | </label> | 105 | </label> |
| @@ -19,20 +19,23 @@ const DEFAULT_SETTINGS = { | |||
| 19 | selectedProfile: null, | 19 | selectedProfile: null, |
| 20 | }; | 20 | }; |
| 21 | 21 | ||
| 22 | const COMMON_COMMANDS = [ | 22 | const CC_COMMANDS = [ |
| 23 | 'api', | 23 | 'api', |
| 24 | 'preset', | 24 | 'preset', |
| 25 | // Do not fix; CC needs to set the API twice because it could be overridden by the preset | ||
| 26 | 'api', | ||
| 25 | 'api-url', | 27 | 'api-url', |
| 26 | 'model', | 28 | 'model', |
| 27 | ]; | ||
| 28 | |||
| 29 | const CC_COMMANDS = [ | ||
| 30 | ...COMMON_COMMANDS, | ||
| 31 | 'proxy', | 29 | 'proxy', |
| 32 | ]; | 30 | ]; |
| 33 | 31 | ||
| 34 | const TC_COMMANDS = [ | 32 | const TC_COMMANDS = [ |
| 35 | ...COMMON_COMMANDS, | 33 | 'api', |
| 34 | 'preset', | ||
| 35 | 'api-url', | ||
| 36 | 'model', | ||
| 37 | 'sysprompt', | ||
| 38 | 'sysprompt-state', | ||
| 36 | 'instruct', | 39 | 'instruct', |
| 37 | 'context', | 40 | 'context', |
| 38 | 'instruct-state', | 41 | 'instruct-state', |
| @@ -45,6 +48,8 @@ const FANCY_NAMES = { | |||
| 45 | 'preset': 'Settings Preset', | 48 | 'preset': 'Settings Preset', |
| 46 | 'model': 'Model', | 49 | 'model': 'Model', |
| 47 | 'proxy': 'Proxy Preset', | 50 | 'proxy': 'Proxy Preset', |
| 51 | 'sysprompt-state': 'Use System Prompt', | ||
| 52 | 'sysprompt': 'System Prompt Name', | ||
| 48 | 'instruct-state': 'Instruct Mode', | 53 | 'instruct-state': 'Instruct Mode', |
| 49 | 'instruct': 'Instruct Template', | 54 | 'instruct': 'Instruct Template', |
| 50 | 'context': 'Context Template', | 55 | 'context': 'Context Template', |
| @@ -180,6 +185,11 @@ async function readProfileFromCommands(mode, profile, cleanUp = false) { | |||
| 180 | } | 185 | } |
| 181 | 186 | ||
| 182 | if (cleanUp) { | 187 | if (cleanUp) { |
| 188 | for (const command of commands) { | ||
| 189 | if (command.endsWith('-state') && profile[command] === 'false') { | ||
| 190 | delete profile[command.replace('-state', '')]; | ||
| 191 | } | ||
| 192 | } | ||
| 183 | for (const command of opposingCommands) { | 193 | for (const command of opposingCommands) { |
| 184 | if (commands.includes(command)) { | 194 | if (commands.includes(command)) { |
| 185 | continue; | 195 | continue; |
| @@ -325,7 +335,7 @@ function renderConnectionProfiles(profiles) { | |||
| 325 | noneOption.selected = !extension_settings.connectionManager.selectedProfile; | 335 | noneOption.selected = !extension_settings.connectionManager.selectedProfile; |
| 326 | profiles.appendChild(noneOption); | 336 | profiles.appendChild(noneOption); |
| 327 | 337 | ||
| 328 | for (const profile of extension_settings.connectionManager.profiles) { | 338 | for (const profile of extension_settings.connectionManager.profiles.sort((a, b) => a.name.localeCompare(b.name))) { |
| 329 | const option = document.createElement('option'); | 339 | const option = document.createElement('option'); |
| 330 | option.value = profile.id; | 340 | option.value = profile.id; |
| 331 | option.textContent = profile.name; | 341 | option.textContent = profile.name; |
| @@ -462,6 +472,31 @@ async function renderDetailsContent(detailsContent) { | |||
| 462 | await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, NONE); | 472 | await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, NONE); |
| 463 | }); | 473 | }); |
| 464 | 474 | ||
| 475 | const renameButton = document.getElementById('rename_connection_profile'); | ||
| 476 | renameButton.addEventListener('click', async () => { | ||
| 477 | const selectedProfile = extension_settings.connectionManager.selectedProfile; | ||
| 478 | const profile = extension_settings.connectionManager.profiles.find(p => p.id === selectedProfile); | ||
| 479 | if (!profile) { | ||
| 480 | console.log('No profile selected'); | ||
| 481 | return; | ||
| 482 | } | ||
| 483 | |||
| 484 | const newName = await Popup.show.input('Enter a new name', null, profile.name, { rows: 2 }); | ||
| 485 | if (!newName) { | ||
| 486 | return; | ||
| 487 | } | ||
| 488 | |||
| 489 | if (extension_settings.connectionManager.profiles.some(p => p.name === newName)) { | ||
| 490 | toastr.error('A profile with the same name already exists.'); | ||
| 491 | return; | ||
| 492 | } | ||
| 493 | |||
| 494 | profile.name = newName; | ||
| 495 | saveSettingsDebounced(); | ||
| 496 | renderConnectionProfiles(profiles); | ||
| 497 | toastr.success('Connection profile renamed', '', { timeOut: 1500 }); | ||
| 498 | }); | ||
| 499 | |||
| 465 | /** @type {HTMLElement} */ | 500 | /** @type {HTMLElement} */ |
| 466 | const viewDetails = document.getElementById('view_connection_profile'); | 501 | const viewDetails = document.getElementById('view_connection_profile'); |
| 467 | const detailsContent = document.getElementById('connection_profile_details_content'); | 502 | const detailsContent = document.getElementById('connection_profile_details_content'); |
| @@ -13,6 +13,7 @@ | |||
| 13 | <i id="view_connection_profile" class="menu_button fa-solid fa-info-circle" title="View connection profile details" data-i18n="[title]View connection profile details"></i> | 13 | <i id="view_connection_profile" class="menu_button fa-solid fa-info-circle" title="View connection profile details" data-i18n="[title]View connection profile details"></i> |
| 14 | <i id="create_connection_profile" class="menu_button fa-solid fa-file-circle-plus" title="Create a new connection profile" data-i18n="[title]Create a new connection profile"></i> | 14 | <i id="create_connection_profile" class="menu_button fa-solid fa-file-circle-plus" title="Create a new connection profile" data-i18n="[title]Create a new connection profile"></i> |
| 15 | <i id="update_connection_profile" class="menu_button fa-solid fa-save" title="Update a connection profile" data-i18n="[title]Update a connection profile"></i> | 15 | <i id="update_connection_profile" class="menu_button fa-solid fa-save" title="Update a connection profile" data-i18n="[title]Update a connection profile"></i> |
| 16 | <i id="rename_connection_profile" class="menu_button fa-solid fa-pencil" title="Rename a connection profile" data-i18n="[title]Rename a connection profile"></i> | ||
| 16 | <i id="reload_connection_profile" class="menu_button fa-solid fa-recycle" title="Reload a connection profile" data-i18n="[title]Reload a connection profile"></i> | 17 | <i id="reload_connection_profile" class="menu_button fa-solid fa-recycle" title="Reload a connection profile" data-i18n="[title]Reload a connection profile"></i> |
| 17 | <i id="delete_connection_profile" class="menu_button fa-solid fa-trash-can" title="Delete a connection profile" data-i18n="[title]Delete a connection profile"></i> | 18 | <i id="delete_connection_profile" class="menu_button fa-solid fa-trash-can" title="Delete a connection profile" data-i18n="[title]Delete a connection profile"></i> |
| 18 | </div> | 19 | </div> |
| @@ -20,7 +20,7 @@ const STREAMING_UPDATE_INTERVAL = 10000; | |||
| 20 | const TALKINGCHECK_UPDATE_INTERVAL = 500; | 20 | const TALKINGCHECK_UPDATE_INTERVAL = 500; |
| 21 | const DEFAULT_FALLBACK_EXPRESSION = 'joy'; | 21 | const DEFAULT_FALLBACK_EXPRESSION = 'joy'; |
| 22 | const FUNCTION_NAME = 'set_emotion'; | 22 | const FUNCTION_NAME = 'set_emotion'; |
| 23 | const DEFAULT_LLM_PROMPT = 'Pause your roleplay. Classify the emotion of the last message. Output just one word, e.g. "joy" or "anger". Choose only one of the following labels: {{labels}}'; | 23 | const DEFAULT_LLM_PROMPT = 'Ignore previous instructions. Classify the emotion of the last message. Output just one word, e.g. "joy" or "anger". Choose only one of the following labels: {{labels}}'; |
| 24 | const DEFAULT_EXPRESSIONS = [ | 24 | const DEFAULT_EXPRESSIONS = [ |
| 25 | 'talkinghead', | 25 | 'talkinghead', |
| 26 | 'admiration', | 26 | 'admiration', |
| @@ -2064,6 +2064,11 @@ function migrateSettings() { | |||
| 2064 | }); | 2064 | }); |
| 2065 | eventSource.on(event_types.MOVABLE_PANELS_RESET, updateVisualNovelModeDebounced); | 2065 | eventSource.on(event_types.MOVABLE_PANELS_RESET, updateVisualNovelModeDebounced); |
| 2066 | eventSource.on(event_types.GROUP_UPDATED, updateVisualNovelModeDebounced); | 2066 | eventSource.on(event_types.GROUP_UPDATED, updateVisualNovelModeDebounced); |
| 2067 | eventSource.on(event_types.EXTRAS_CONNECTED, () => { | ||
| 2068 | if (extension_settings.expressions.talkinghead) { | ||
| 2069 | setTalkingHeadState(extension_settings.expressions.talkinghead); | ||
| 2070 | } | ||
| 2071 | }); | ||
| 2067 | 2072 | ||
| 2068 | const localEnumProviders = { | 2073 | const localEnumProviders = { |
| 2069 | expressions: () => getCachedExpressions().map(expression => { | 2074 | expressions: () => getCachedExpressions().map(expression => { |
| @@ -102,7 +102,7 @@ const prompt_builders = { | |||
| 102 | RAW_NON_BLOCKING: 2, | 102 | RAW_NON_BLOCKING: 2, |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | const defaultPrompt = '[Pause your roleplay. Summarize the most important facts and events in the story so far. If a summary already exists in your memory, use that as a base and expand with new facts. Limit the summary to {{words}} words or less. Your response should include nothing but the summary.]'; | 105 | const defaultPrompt = 'Ignore previous instructions. Summarize the most important facts and events in the story so far. If a summary already exists in your memory, use that as a base and expand with new facts. Limit the summary to {{words}} words or less. Your response should include nothing but the summary.'; |
| 106 | const defaultTemplate = '[Summary: {{summary}}]'; | 106 | const defaultTemplate = '[Summary: {{summary}}]'; |
| 107 | 107 | ||
| 108 | const defaultSettings = { | 108 | const defaultSettings = { |
| @@ -1904,6 +1904,7 @@ export class QuickReply { | |||
| 1904 | executeOnAi: this.executeOnAi, | 1904 | executeOnAi: this.executeOnAi, |
| 1905 | executeOnChatChange: this.executeOnChatChange, | 1905 | executeOnChatChange: this.executeOnChatChange, |
| 1906 | executeOnGroupMemberDraft: this.executeOnGroupMemberDraft, | 1906 | executeOnGroupMemberDraft: this.executeOnGroupMemberDraft, |
| 1907 | executeOnNewChat: this.executeOnNewChat, | ||
| 1907 | automationId: this.automationId, | 1908 | automationId: this.automationId, |
| 1908 | }; | 1909 | }; |
| 1909 | } | 1910 | } |
| @@ -35,6 +35,7 @@ export class SlashCommandHandler { | |||
| 35 | if (qr.executeOnUser) icons += enumIcons.user; | 35 | if (qr.executeOnUser) icons += enumIcons.user; |
| 36 | if (qr.executeOnAi) icons += enumIcons.assistant; | 36 | if (qr.executeOnAi) icons += enumIcons.assistant; |
| 37 | if (qr.executeOnChatChange) icons += '💬'; | 37 | if (qr.executeOnChatChange) icons += '💬'; |
| 38 | if (qr.executeOnNewChat) icons += '🆕'; | ||
| 38 | if (qr.executeOnGroupMemberDraft) icons += enumIcons.group; | 39 | if (qr.executeOnGroupMemberDraft) icons += enumIcons.group; |
| 39 | return icons; | 40 | return icons; |
| 40 | } | 41 | } |
| @@ -265,6 +266,7 @@ export class SlashCommandHandler { | |||
| 265 | new SlashCommandNamedArgument('user', 'auto execute on user message, e.g., user=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'), | 266 | new SlashCommandNamedArgument('user', 'auto execute on user message, e.g., user=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'), |
| 266 | new SlashCommandNamedArgument('bot', 'auto execute on AI message, e.g., bot=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'), | 267 | new SlashCommandNamedArgument('bot', 'auto execute on AI message, e.g., bot=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'), |
| 267 | new SlashCommandNamedArgument('load', 'auto execute on chat load, e.g., load=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'), | 268 | new SlashCommandNamedArgument('load', 'auto execute on chat load, e.g., load=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'), |
| 269 | new SlashCommandNamedArgument('new', 'auto execute on new chat, e.g., new=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'), | ||
| 268 | new SlashCommandNamedArgument('group', 'auto execute on group member selection, e.g., group=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'), | 270 | new SlashCommandNamedArgument('group', 'auto execute on group member selection, e.g., group=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'), |
| 269 | new SlashCommandNamedArgument('title', 'title / tooltip to be shown on button, e.g., title="My Fancy Button"', [ARGUMENT_TYPE.STRING], false), | 271 | new SlashCommandNamedArgument('title', 'title / tooltip to be shown on button, e.g., title="My Fancy Button"', [ARGUMENT_TYPE.STRING], false), |
| 270 | ]; | 272 | ]; |
| @@ -857,6 +859,7 @@ export class SlashCommandHandler { | |||
| 857 | executeOnUser: isTrueBoolean(args.user), | 859 | executeOnUser: isTrueBoolean(args.user), |
| 858 | executeOnAi: isTrueBoolean(args.bot), | 860 | executeOnAi: isTrueBoolean(args.bot), |
| 859 | executeOnChatChange: isTrueBoolean(args.load), | 861 | executeOnChatChange: isTrueBoolean(args.load), |
| 862 | executeOnNewChat: isTrueBoolean(args.new), | ||
| 860 | executeOnGroupMemberDraft: isTrueBoolean(args.group), | 863 | executeOnGroupMemberDraft: isTrueBoolean(args.group), |
| 861 | automationId: args.automationId ?? '', | 864 | automationId: args.automationId ?? '', |
| 862 | }, | 865 | }, |
| @@ -889,6 +892,7 @@ export class SlashCommandHandler { | |||
| 889 | executeOnAi: args.bot === undefined ? undefined : isTrueBoolean(args.bot), | 892 | executeOnAi: args.bot === undefined ? undefined : isTrueBoolean(args.bot), |
| 890 | executeOnChatChange: args.load === undefined ? undefined : isTrueBoolean(args.load), | 893 | executeOnChatChange: args.load === undefined ? undefined : isTrueBoolean(args.load), |
| 891 | executeOnGroupMemberDraft: args.group === undefined ? undefined : isTrueBoolean(args.group), | 894 | executeOnGroupMemberDraft: args.group === undefined ? undefined : isTrueBoolean(args.group), |
| 895 | executeOnNewChat: args.new === undefined ? undefined : isTrueBoolean(args.new), | ||
| 892 | automationId: args.automationId ?? '', | 896 | automationId: args.automationId ?? '', |
| 893 | }, | 897 | }, |
| 894 | ); | 898 | ); |
| @@ -13,7 +13,7 @@ import { createThumbnail, isValidUrl } from '../utils.js'; | |||
| 13 | */ | 13 | */ |
| 14 | export async function getMultimodalCaption(base64Img, prompt) { | 14 | export async function getMultimodalCaption(base64Img, prompt) { |
| 15 | const useReverseProxy = | 15 | const useReverseProxy = |
| 16 | (['openai', 'anthropic', 'google'].includes(extension_settings.caption.multimodal_api)) | 16 | (['openai', 'anthropic', 'google', 'mistral'].includes(extension_settings.caption.multimodal_api)) |
| 17 | && extension_settings.caption.allow_reverse_proxy | 17 | && extension_settings.caption.allow_reverse_proxy |
| 18 | && oai_settings.reverse_proxy | 18 | && oai_settings.reverse_proxy |
| 19 | && isValidUrl(oai_settings.reverse_proxy); | 19 | && isValidUrl(oai_settings.reverse_proxy); |
| @@ -36,7 +36,7 @@ export async function getMultimodalCaption(base64Img, prompt) { | |||
| 36 | const isVllm = extension_settings.caption.multimodal_api === 'vllm'; | 36 | const isVllm = extension_settings.caption.multimodal_api === 'vllm'; |
| 37 | const base64Bytes = base64Img.length * 0.75; | 37 | const base64Bytes = base64Img.length * 0.75; |
| 38 | const compressionLimit = 2 * 1024 * 1024; | 38 | const compressionLimit = 2 * 1024 * 1024; |
| 39 | if ((['google', 'openrouter'].includes(extension_settings.caption.multimodal_api) && base64Bytes > compressionLimit) || isOoba || isKoboldCpp) { | 39 | if ((['google', 'openrouter', 'mistral'].includes(extension_settings.caption.multimodal_api) && base64Bytes > compressionLimit) || isOoba || isKoboldCpp) { |
| 40 | const maxSide = 1024; | 40 | const maxSide = 1024; |
| 41 | base64Img = await createThumbnail(base64Img, maxSide, maxSide, 'image/jpeg'); | 41 | base64Img = await createThumbnail(base64Img, maxSide, maxSide, 'image/jpeg'); |
| 42 | } | 42 | } |
| @@ -139,6 +139,10 @@ function throwIfInvalidModel(useReverseProxy) { | |||
| 139 | throw new Error('Google AI Studio API key is not set.'); | 139 | throw new Error('Google AI Studio API key is not set.'); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | if (extension_settings.caption.multi_modal_api === 'mistral' && !secret_state[SECRET_KEYS.MISTRALAI] && !useReverseProxy) { | ||
| 143 | throw new Error('Mistral AI API key is not set.'); | ||
| 144 | } | ||
| 145 | |||
| 142 | if (extension_settings.caption.multimodal_api === 'ollama' && !textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]) { | 146 | if (extension_settings.caption.multimodal_api === 'ollama' && !textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]) { |
| 143 | throw new Error('Ollama server URL is not set.'); | 147 | throw new Error('Ollama server URL is not set.'); |
| 144 | } | 148 | } |
| @@ -125,15 +125,14 @@ const messageTrigger = { | |||
| 125 | const promptTemplates = { | 125 | const promptTemplates = { |
| 126 | // Not really a prompt template, rather an outcome message template | 126 | // Not really a prompt template, rather an outcome message template |
| 127 | [generationMode.MESSAGE]: '[{{char}} sends a picture that contains: {{prompt}}].', | 127 | [generationMode.MESSAGE]: '[{{char}} sends a picture that contains: {{prompt}}].', |
| 128 | /*OLD: [generationMode.CHARACTER]: "Pause your roleplay and provide comma-delimited list of phrases and keywords which describe {{char}}'s physical appearance and clothing. Ignore {{char}}'s personality traits, and chat history when crafting this description. End your response once the comma-delimited list is complete. Do not roleplay when writing this description, and do not attempt to continue the story.", */ | 128 | [generationMode.CHARACTER]: 'In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'full body portrait,\'', |
| 129 | [generationMode.CHARACTER]: '[In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'full body portrait,\']', | ||
| 130 | //face-specific prompt | 129 | //face-specific prompt |
| 131 | [generationMode.FACE]: '[In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, facial features and expressions, occupation, hair and hair accessories (if any), what they are wearing on their upper body (if anything). Do not describe anything below their neck. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'close up facial portrait,\']', | 130 | [generationMode.FACE]: 'In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, facial features and expressions, occupation, hair and hair accessories (if any), what they are wearing on their upper body (if anything). Do not describe anything below their neck. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'close up facial portrait,\'', |
| 132 | //prompt for only the last message | 131 | //prompt for only the last message |
| 133 | [generationMode.USER]: '[Pause your roleplay and provide a detailed description of {{user}}\'s physical appearance from the perspective of {{char}} in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'full body portrait,\'. Ignore the rest of the story when crafting this description. Do not roleplay as {{char}} when writing this description, and do not attempt to continue the story.]', | 132 | [generationMode.USER]: 'Ignore previous instructions and provide a detailed description of {{user}}\'s physical appearance from the perspective of {{char}} in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'full body portrait,\'. Ignore the rest of the story when crafting this description. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.', |
| 134 | [generationMode.SCENARIO]: '[Pause your roleplay and provide a detailed description for all of the following: a brief recap of recent events in the story, {{char}}\'s appearance, and {{char}}\'s surroundings. Do not roleplay while writing this description.]', | 133 | [generationMode.SCENARIO]: 'Ignore previous instructions and provide a detailed description for all of the following: a brief recap of recent events in the story, {{char}}\'s appearance, and {{char}}\'s surroundings. Do not reply as {{char}} while writing this description.', |
| 135 | 134 | ||
| 136 | [generationMode.NOW]: `[Pause your roleplay. Your next response must be formatted as a single comma-delimited list of concise keywords. The list will describe of the visual details included in the last chat message. | 135 | [generationMode.NOW]: `Ignore previous instructions. Your next response must be formatted as a single comma-delimited list of concise keywords. The list will describe of the visual details included in the last chat message. |
| 137 | 136 | ||
| 138 | Only mention characters by using pronouns ('he','his','she','her','it','its') or neutral nouns ('male', 'the man', 'female', 'the woman'). | 137 | Only mention characters by using pronouns ('he','his','she','her','it','its') or neutral nouns ('male', 'the man', 'female', 'the woman'). |
| 139 | 138 | ||
| @@ -155,14 +154,14 @@ const promptTemplates = { | |||
| 155 | If character actions involve direct physical interaction with another character, mention specifically which body parts interacting and how. | 154 | If character actions involve direct physical interaction with another character, mention specifically which body parts interacting and how. |
| 156 | 155 | ||
| 157 | A correctly formatted example response would be: | 156 | A correctly formatted example response would be: |
| 158 | '(location),(character list by gender),(primary action), (relative character position) POV, (character 1's description and actions), (character 2's description and actions)']`, | 157 | '(location),(character list by gender),(primary action), (relative character position) POV, (character 1's description and actions), (character 2's description and actions)'`, |
| 159 | 158 | ||
| 160 | [generationMode.RAW_LAST]: '[Pause your roleplay and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not roleplay at all in your response. Do not continue the roleplay story.]', | 159 | [generationMode.RAW_LAST]: 'Ignore previous instructions and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.', |
| 161 | [generationMode.BACKGROUND]: '[Pause your roleplay and provide a detailed description of {{char}}\'s surroundings in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: location, time of day, weather, lighting, and any other relevant details. Do not include descriptions of characters and non-visual qualities such as names, personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'background,\'. Ignore the rest of the story when crafting this description. Do not roleplay as {{user}} when writing this description, and do not attempt to continue the story.]', | 160 | [generationMode.BACKGROUND]: 'Ignore previous instructions and provide a detailed description of {{char}}\'s surroundings in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: location, time of day, weather, lighting, and any other relevant details. Do not include descriptions of characters and non-visual qualities such as names, personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'background,\'. Ignore the rest of the story when crafting this description. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.', |
| 162 | [generationMode.FACE_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "close-up portrait".', | 161 | [generationMode.FACE_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "close-up portrait".', |
| 163 | [generationMode.CHARACTER_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "full body portrait".', | 162 | [generationMode.CHARACTER_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "full body portrait".', |
| 164 | [generationMode.USER_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "full body portrait".', | 163 | [generationMode.USER_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "full body portrait".', |
| 165 | [generationMode.FREE_EXTENDED]: 'Pause your roleplay and provide an exhaustive comma-separated list of tags describing the appearance of "{0}" in great detail. Start with {{charPrefix}} (sic) if the subject is associated with {{char}}.', | 164 | [generationMode.FREE_EXTENDED]: 'Ignore previous instructions and provide an exhaustive comma-separated list of tags describing the appearance of "{0}" in great detail. Start with {{charPrefix}} (sic) if the subject is associated with {{char}}.', |
| 166 | }; | 165 | }; |
| 167 | 166 | ||
| 168 | const defaultPrefix = 'best quality, absurdres, aesthetic,'; | 167 | const defaultPrefix = 'best quality, absurdres, aesthetic,'; |
| @@ -3813,7 +3812,10 @@ jQuery(async () => { | |||
| 3813 | ], | 3812 | ], |
| 3814 | helpString: ` | 3813 | helpString: ` |
| 3815 | <div> | 3814 | <div> |
| 3816 | Requests to generate an image and posts it to chat (unless <code>quiet=true</code> argument is specified).</code>. | 3815 | Requests to generate an image and posts it to chat (unless <code>quiet=true</code> argument is specified). |
| 3816 | </div> | ||
| 3817 | <div> | ||
| 3818 | Supported arguments: <code>${Object.values(triggerWords).flat().join(', ')}</code>. | ||
| 3817 | </div> | 3819 | </div> |
| 3818 | <div> | 3820 | <div> |
| 3819 | Anything else would trigger a "free mode" to make generate whatever you prompted. Example: <code>/imagine apple tree</code> would generate a picture of an apple tree. Returns a link to the generated image. | 3821 | Anything else would trigger a "free mode" to make generate whatever you prompted. Example: <code>/imagine apple tree</code> would generate a picture of an apple tree. Returns a link to the generated image. |
| @@ -349,7 +349,7 @@ | |||
| 349 | </div> | 349 | </div> |
| 350 | </div> | 350 | </div> |
| 351 | 351 | ||
| 352 | <div class="flex-container marginTopBot5" data-sd-source="auto,vlad,extras,horde,drawthings,comfy"> | 352 | <div class="flex-container marginTopBot5" data-sd-source="auto,vlad,extras,horde,drawthings"> |
| 353 | <label class="flex1 checkbox_label"> | 353 | <label class="flex1 checkbox_label"> |
| 354 | <input id="sd_restore_faces" type="checkbox" /> | 354 | <input id="sd_restore_faces" type="checkbox" /> |
| 355 | <small data-i18n="Restore Faces">Restore Faces</small> | 355 | <small data-i18n="Restore Faces">Restore Faces</small> |
| @@ -56,7 +56,7 @@ const settings = { | |||
| 56 | summarize: false, | 56 | summarize: false, |
| 57 | summarize_sent: false, | 57 | summarize_sent: false, |
| 58 | summary_source: 'main', | 58 | summary_source: 'main', |
| 59 | summary_prompt: 'Pause your roleplay. Summarize the most important parts of the message. Limit yourself to 250 words or less. Your response should include nothing but the summary.', | 59 | summary_prompt: 'Ignore previous instructions. Summarize the most important parts of the message. Limit yourself to 250 words or less. Your response should include nothing but the summary.', |
| 60 | force_chunk_delimiter: '', | 60 | force_chunk_delimiter: '', |
| 61 | 61 | ||
| 62 | // For chats | 62 | // For chats |
| @@ -718,7 +718,7 @@ async function getQueryText(chat, initiator) { | |||
| 718 | async function getSavedHashes(collectionId) { | 718 | async function getSavedHashes(collectionId) { |
| 719 | const response = await fetch('/api/vector/list', { | 719 | const response = await fetch('/api/vector/list', { |
| 720 | method: 'POST', | 720 | method: 'POST', |
| 721 | headers: getRequestHeaders(), | 721 | headers: getVectorHeaders(), |
| 722 | body: JSON.stringify({ | 722 | body: JSON.stringify({ |
| 723 | collectionId: collectionId, | 723 | collectionId: collectionId, |
| 724 | source: settings.source, | 724 | source: settings.source, |
| @@ -737,25 +737,43 @@ function getVectorHeaders() { | |||
| 737 | const headers = getRequestHeaders(); | 737 | const headers = getRequestHeaders(); |
| 738 | switch (settings.source) { | 738 | switch (settings.source) { |
| 739 | case 'extras': | 739 | case 'extras': |
| 740 | addExtrasHeaders(headers); | 740 | Object.assign(headers, { |
| 741 | 'X-Extras-Url': extension_settings.apiUrl, | ||
| 742 | 'X-Extras-Key': extension_settings.apiKey, | ||
| 743 | }); | ||
| 741 | break; | 744 | break; |
| 742 | case 'togetherai': | 745 | case 'togetherai': |
| 743 | addTogetherAiHeaders(headers); | 746 | Object.assign(headers, { |
| 747 | 'X-Togetherai-Model': extension_settings.vectors.togetherai_model, | ||
| 748 | }); | ||
| 744 | break; | 749 | break; |
| 745 | case 'openai': | 750 | case 'openai': |
| 746 | addOpenAiHeaders(headers); | 751 | Object.assign(headers, { |
| 752 | 'X-OpenAI-Model': extension_settings.vectors.openai_model, | ||
| 753 | }); | ||
| 747 | break; | 754 | break; |
| 748 | case 'cohere': | 755 | case 'cohere': |
| 749 | addCohereHeaders(headers); | 756 | Object.assign(headers, { |
| 757 | 'X-Cohere-Model': extension_settings.vectors.cohere_model, | ||
| 758 | }); | ||
| 750 | break; | 759 | break; |
| 751 | case 'ollama': | 760 | case 'ollama': |
| 752 | addOllamaHeaders(headers); | 761 | Object.assign(headers, { |
| 762 | 'X-Ollama-Model': extension_settings.vectors.ollama_model, | ||
| 763 | 'X-Ollama-URL': textgenerationwebui_settings.server_urls[textgen_types.OLLAMA], | ||
| 764 | 'X-Ollama-Keep': !!extension_settings.vectors.ollama_keep, | ||
| 765 | }); | ||
| 753 | break; | 766 | break; |
| 754 | case 'llamacpp': | 767 | case 'llamacpp': |
| 755 | addLlamaCppHeaders(headers); | 768 | Object.assign(headers, { |
| 769 | 'X-LlamaCpp-URL': textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP], | ||
| 770 | }); | ||
| 756 | break; | 771 | break; |
| 757 | case 'vllm': | 772 | case 'vllm': |
| 758 | addVllmHeaders(headers); | 773 | Object.assign(headers, { |
| 774 | 'X-Vllm-URL': textgenerationwebui_settings.server_urls[textgen_types.VLLM], | ||
| 775 | 'X-Vllm-Model': extension_settings.vectors.vllm_model, | ||
| 776 | }); | ||
| 759 | break; | 777 | break; |
| 760 | default: | 778 | default: |
| 761 | break; | 779 | break; |
| @@ -764,81 +782,6 @@ function getVectorHeaders() { | |||
| 764 | } | 782 | } |
| 765 | 783 | ||
| 766 | /** | 784 | /** |
| 767 | * Add headers for the Extras API source. | ||
| 768 | * @param {object} headers Headers object | ||
| 769 | */ | ||
| 770 | function addExtrasHeaders(headers) { | ||
| 771 | console.log(`Vector source is extras, populating API URL: ${extension_settings.apiUrl}`); | ||
| 772 | Object.assign(headers, { | ||
| 773 | 'X-Extras-Url': extension_settings.apiUrl, | ||
| 774 | 'X-Extras-Key': extension_settings.apiKey, | ||
| 775 | }); | ||
| 776 | } | ||
| 777 | |||
| 778 | /** | ||
| 779 | * Add headers for the TogetherAI API source. | ||
| 780 | * @param {object} headers Headers object | ||
| 781 | */ | ||
| 782 | function addTogetherAiHeaders(headers) { | ||
| 783 | Object.assign(headers, { | ||
| 784 | 'X-Togetherai-Model': extension_settings.vectors.togetherai_model, | ||
| 785 | }); | ||
| 786 | } | ||
| 787 | |||
| 788 | /** | ||
| 789 | * Add headers for the OpenAI API source. | ||
| 790 | * @param {object} headers Header object | ||
| 791 | */ | ||
| 792 | function addOpenAiHeaders(headers) { | ||
| 793 | Object.assign(headers, { | ||
| 794 | 'X-OpenAI-Model': extension_settings.vectors.openai_model, | ||
| 795 | }); | ||
| 796 | } | ||
| 797 | |||
| 798 | /** | ||
| 799 | * Add headers for the Cohere API source. | ||
| 800 | * @param {object} headers Header object | ||
| 801 | */ | ||
| 802 | function addCohereHeaders(headers) { | ||
| 803 | Object.assign(headers, { | ||
| 804 | 'X-Cohere-Model': extension_settings.vectors.cohere_model, | ||
| 805 | }); | ||
| 806 | } | ||
| 807 | |||
| 808 | /** | ||
| 809 | * Add headers for the Ollama API source. | ||
| 810 | * @param {object} headers Header object | ||
| 811 | */ | ||
| 812 | function addOllamaHeaders(headers) { | ||
| 813 | Object.assign(headers, { | ||
| 814 | 'X-Ollama-Model': extension_settings.vectors.ollama_model, | ||
| 815 | 'X-Ollama-URL': textgenerationwebui_settings.server_urls[textgen_types.OLLAMA], | ||
| 816 | 'X-Ollama-Keep': !!extension_settings.vectors.ollama_keep, | ||
| 817 | }); | ||
| 818 | } | ||
| 819 | |||
| 820 | /** | ||
| 821 | * Add headers for the LlamaCpp API source. | ||
| 822 | * @param {object} headers Header object | ||
| 823 | */ | ||
| 824 | function addLlamaCppHeaders(headers) { | ||
| 825 | Object.assign(headers, { | ||
| 826 | 'X-LlamaCpp-URL': textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP], | ||
| 827 | }); | ||
| 828 | } | ||
| 829 | |||
| 830 | /** | ||
| 831 | * Add headers for the VLLM API source. | ||
| 832 | * @param {object} headers Header object | ||
| 833 | */ | ||
| 834 | function addVllmHeaders(headers) { | ||
| 835 | Object.assign(headers, { | ||
| 836 | 'X-Vllm-URL': textgenerationwebui_settings.server_urls[textgen_types.VLLM], | ||
| 837 | 'X-Vllm-Model': extension_settings.vectors.vllm_model, | ||
| 838 | }); | ||
| 839 | } | ||
| 840 | |||
| 841 | /** | ||
| 842 | * Inserts vector items into a collection | 785 | * Inserts vector items into a collection |
| 843 | * @param {string} collectionId - The collection to insert into | 786 | * @param {string} collectionId - The collection to insert into |
| 844 | * @param {{ hash: number, text: string }[]} items - The items to insert | 787 | * @param {{ hash: number, text: string }[]} items - The items to insert |
| @@ -901,7 +844,7 @@ function throwIfSourceInvalid() { | |||
| 901 | async function deleteVectorItems(collectionId, hashes) { | 844 | async function deleteVectorItems(collectionId, hashes) { |
| 902 | const response = await fetch('/api/vector/delete', { | 845 | const response = await fetch('/api/vector/delete', { |
| 903 | method: 'POST', | 846 | method: 'POST', |
| 904 | headers: getRequestHeaders(), | 847 | headers: getVectorHeaders(), |
| 905 | body: JSON.stringify({ | 848 | body: JSON.stringify({ |
| 906 | collectionId: collectionId, | 849 | collectionId: collectionId, |
| 907 | hashes: hashes, | 850 | hashes: hashes, |
| @@ -987,7 +930,7 @@ async function purgeFileVectorIndex(fileUrl) { | |||
| 987 | 930 | ||
| 988 | const response = await fetch('/api/vector/purge', { | 931 | const response = await fetch('/api/vector/purge', { |
| 989 | method: 'POST', | 932 | method: 'POST', |
| 990 | headers: getRequestHeaders(), | 933 | headers: getVectorHeaders(), |
| 991 | body: JSON.stringify({ | 934 | body: JSON.stringify({ |
| 992 | collectionId: collectionId, | 935 | collectionId: collectionId, |
| 993 | }), | 936 | }), |
| @@ -1016,7 +959,7 @@ async function purgeVectorIndex(collectionId) { | |||
| 1016 | 959 | ||
| 1017 | const response = await fetch('/api/vector/purge', { | 960 | const response = await fetch('/api/vector/purge', { |
| 1018 | method: 'POST', | 961 | method: 'POST', |
| 1019 | headers: getRequestHeaders(), | 962 | headers: getVectorHeaders(), |
| 1020 | body: JSON.stringify({ | 963 | body: JSON.stringify({ |
| 1021 | collectionId: collectionId, | 964 | collectionId: collectionId, |
| 1022 | }), | 965 | }), |
| @@ -1041,7 +984,7 @@ async function purgeAllVectorIndexes() { | |||
| 1041 | try { | 984 | try { |
| 1042 | const response = await fetch('/api/vector/purge-all', { | 985 | const response = await fetch('/api/vector/purge-all', { |
| 1043 | method: 'POST', | 986 | method: 'POST', |
| 1044 | headers: getRequestHeaders(), | 987 | headers: getVectorHeaders(), |
| 1045 | }); | 988 | }); |
| 1046 | 989 | ||
| 1047 | if (!response.ok) { | 990 | if (!response.ok) { |
| @@ -1056,6 +999,25 @@ async function purgeAllVectorIndexes() { | |||
| 1056 | } | 999 | } |
| 1057 | } | 1000 | } |
| 1058 | 1001 | ||
| 1002 | async function isModelScopesEnabled() { | ||
| 1003 | try { | ||
| 1004 | const response = await fetch('/api/vector/scopes-enabled', { | ||
| 1005 | method: 'GET', | ||
| 1006 | headers: getVectorHeaders(), | ||
| 1007 | }); | ||
| 1008 | |||
| 1009 | if (!response.ok) { | ||
| 1010 | return false; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | const data = await response.json(); | ||
| 1014 | return data?.enabled ?? false; | ||
| 1015 | } catch (error) { | ||
| 1016 | console.error('Vectors: Failed to check model scopes', error); | ||
| 1017 | return false; | ||
| 1018 | } | ||
| 1019 | } | ||
| 1020 | |||
| 1059 | function toggleSettings() { | 1021 | function toggleSettings() { |
| 1060 | $('#vectors_files_settings').toggle(!!settings.enabled_files); | 1022 | $('#vectors_files_settings').toggle(!!settings.enabled_files); |
| 1061 | $('#vectors_chats_settings').toggle(!!settings.enabled_chats); | 1023 | $('#vectors_chats_settings').toggle(!!settings.enabled_chats); |
| @@ -1320,6 +1282,7 @@ jQuery(async () => { | |||
| 1320 | } | 1282 | } |
| 1321 | 1283 | ||
| 1322 | Object.assign(settings, extension_settings.vectors); | 1284 | Object.assign(settings, extension_settings.vectors); |
| 1285 | const scopesEnabled = await isModelScopesEnabled(); | ||
| 1323 | 1286 | ||
| 1324 | // Migrate from TensorFlow to Transformers | 1287 | // Migrate from TensorFlow to Transformers |
| 1325 | settings.source = settings.source !== 'local' ? settings.source : 'transformers'; | 1288 | settings.source = settings.source !== 'local' ? settings.source : 'transformers'; |
| @@ -1371,31 +1334,31 @@ jQuery(async () => { | |||
| 1371 | saveSettingsDebounced(); | 1334 | saveSettingsDebounced(); |
| 1372 | }); | 1335 | }); |
| 1373 | $('#vectors_togetherai_model').val(settings.togetherai_model).on('change', () => { | 1336 | $('#vectors_togetherai_model').val(settings.togetherai_model).on('change', () => { |
| 1374 | $('#vectors_modelWarning').show(); | 1337 | !scopesEnabled && $('#vectors_modelWarning').show(); |
| 1375 | settings.togetherai_model = String($('#vectors_togetherai_model').val()); | 1338 | settings.togetherai_model = String($('#vectors_togetherai_model').val()); |
| 1376 | Object.assign(extension_settings.vectors, settings); | 1339 | Object.assign(extension_settings.vectors, settings); |
| 1377 | saveSettingsDebounced(); | 1340 | saveSettingsDebounced(); |
| 1378 | }); | 1341 | }); |
| 1379 | $('#vectors_openai_model').val(settings.openai_model).on('change', () => { | 1342 | $('#vectors_openai_model').val(settings.openai_model).on('change', () => { |
| 1380 | $('#vectors_modelWarning').show(); | 1343 | !scopesEnabled && $('#vectors_modelWarning').show(); |
| 1381 | settings.openai_model = String($('#vectors_openai_model').val()); | 1344 | settings.openai_model = String($('#vectors_openai_model').val()); |
| 1382 | Object.assign(extension_settings.vectors, settings); | 1345 | Object.assign(extension_settings.vectors, settings); |
| 1383 | saveSettingsDebounced(); | 1346 | saveSettingsDebounced(); |
| 1384 | }); | 1347 | }); |
| 1385 | $('#vectors_cohere_model').val(settings.cohere_model).on('change', () => { | 1348 | $('#vectors_cohere_model').val(settings.cohere_model).on('change', () => { |
| 1386 | $('#vectors_modelWarning').show(); | 1349 | !scopesEnabled && $('#vectors_modelWarning').show(); |
| 1387 | settings.cohere_model = String($('#vectors_cohere_model').val()); | 1350 | settings.cohere_model = String($('#vectors_cohere_model').val()); |
| 1388 | Object.assign(extension_settings.vectors, settings); | 1351 | Object.assign(extension_settings.vectors, settings); |
| 1389 | saveSettingsDebounced(); | 1352 | saveSettingsDebounced(); |
| 1390 | }); | 1353 | }); |
| 1391 | $('#vectors_ollama_model').val(settings.ollama_model).on('input', () => { | 1354 | $('#vectors_ollama_model').val(settings.ollama_model).on('input', () => { |
| 1392 | $('#vectors_modelWarning').show(); | 1355 | !scopesEnabled && $('#vectors_modelWarning').show(); |
| 1393 | settings.ollama_model = String($('#vectors_ollama_model').val()); | 1356 | settings.ollama_model = String($('#vectors_ollama_model').val()); |
| 1394 | Object.assign(extension_settings.vectors, settings); | 1357 | Object.assign(extension_settings.vectors, settings); |
| 1395 | saveSettingsDebounced(); | 1358 | saveSettingsDebounced(); |
| 1396 | }); | 1359 | }); |
| 1397 | $('#vectors_vllm_model').val(settings.vllm_model).on('input', () => { | 1360 | $('#vectors_vllm_model').val(settings.vllm_model).on('input', () => { |
| 1398 | $('#vectors_modelWarning').show(); | 1361 | !scopesEnabled && $('#vectors_modelWarning').show(); |
| 1399 | settings.vllm_model = String($('#vectors_vllm_model').val()); | 1362 | settings.vllm_model = String($('#vectors_vllm_model').val()); |
| 1400 | Object.assign(extension_settings.vectors, settings); | 1363 | Object.assign(extension_settings.vectors, settings); |
| 1401 | saveSettingsDebounced(); | 1364 | saveSettingsDebounced(); |
| @@ -98,8 +98,9 @@ | |||
| 98 | 98 | ||
| 99 | <small id="vectors_modelWarning"> | 99 | <small id="vectors_modelWarning"> |
| 100 | <i class="fa-solid fa-exclamation-triangle"></i> | 100 | <i class="fa-solid fa-exclamation-triangle"></i> |
| 101 | <span data-i18n="Vectors Model Warning"> | 101 | <span> |
| 102 | It is recommended to purge vectors when changing the model mid-chat. Otherwise, it will lead to sub-par results. | 102 | Set <code>vectors.enableModelScopes</code> to true in config.yaml to switch between vectorization models without needing to purge existing vectors. |
| 103 | This option will soon be enabled by default. | ||
| 103 | </span> | 104 | </span> |
| 104 | </small> | 105 | </small> |
| 105 | 106 | ||
| @@ -1,10 +1,10 @@ | |||
| 1 | import { | 1 | import { |
| 2 | saveSettingsDebounced, | 2 | amount_gen, |
| 3 | callPopup, | 3 | callPopup, |
| 4 | setGenerationProgress, | ||
| 5 | getRequestHeaders, | 4 | getRequestHeaders, |
| 6 | max_context, | 5 | max_context, |
| 7 | amount_gen, | 6 | saveSettingsDebounced, |
| 7 | setGenerationProgress, | ||
| 8 | } from '../script.js'; | 8 | } from '../script.js'; |
| 9 | import { SECRET_KEYS, writeSecret } from './secrets.js'; | 9 | import { SECRET_KEYS, writeSecret } from './secrets.js'; |
| 10 | import { delay } from './utils.js'; | 10 | import { delay } from './utils.js'; |
| @@ -45,8 +45,7 @@ async function getWorkers(force) { | |||
| 45 | headers: getRequestHeaders(), | 45 | headers: getRequestHeaders(), |
| 46 | body: JSON.stringify({ force }), | 46 | body: JSON.stringify({ force }), |
| 47 | }); | 47 | }); |
| 48 | const data = await response.json(); | 48 | return await response.json(); |
| 49 | return data; | ||
| 50 | } | 49 | } |
| 51 | 50 | ||
| 52 | /** | 51 | /** |
| @@ -61,16 +60,18 @@ async function getModels(force) { | |||
| 61 | body: JSON.stringify({ force }), | 60 | body: JSON.stringify({ force }), |
| 62 | }); | 61 | }); |
| 63 | const data = await response.json(); | 62 | const data = await response.json(); |
| 63 | console.log('getModels', data); | ||
| 64 | return data; | 64 | return data; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | |||
| 67 | /** | 68 | /** |
| 68 | * Gets the status of a Horde task. | 69 | * Gets the status of a Horde task. |
| 69 | * @param {string} taskId Task ID | 70 | * @param {string} taskId Task ID |
| 70 | * @returns {Promise<Object>} Task status | 71 | * @returns {Promise<Object>} Task status |
| 71 | */ | 72 | */ |
| 72 | async function getTaskStatus(taskId) { | 73 | async function getTaskStatus(taskId) { |
| 73 | const response = await fetch('/api/horde/task-status', { | 74 | const response = await fetch('/api/horde/task-status', { |
| 74 | method: 'POST', | 75 | method: 'POST', |
| 75 | headers: getRequestHeaders(), | 76 | headers: getRequestHeaders(), |
| 76 | body: JSON.stringify({ taskId }), | 77 | body: JSON.stringify({ taskId }), |
| @@ -80,8 +81,7 @@ async function getTaskStatus(taskId) { | |||
| 80 | throw new Error(`Failed to get task status: ${response.statusText}`); | 81 | throw new Error(`Failed to get task status: ${response.statusText}`); |
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | const data = await response.json(); | 84 | return await response.json(); |
| 84 | return data; | ||
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | /** | 87 | /** |
| @@ -148,7 +148,7 @@ async function adjustHordeGenerationParams(max_context_length, max_length) { | |||
| 148 | 148 | ||
| 149 | for (const model of selectedModels) { | 149 | for (const model of selectedModels) { |
| 150 | for (const worker of workers) { | 150 | for (const worker of workers) { |
| 151 | if (model.cluster == worker.cluster && worker.models.includes(model.name)) { | 151 | if (model.cluster === worker.cluster && worker.models.includes(model.name)) { |
| 152 | // Skip workers that are not trusted if the option is enabled | 152 | // Skip workers that are not trusted if the option is enabled |
| 153 | if (horde_settings.trusted_workers_only && !worker.trusted) { | 153 | if (horde_settings.trusted_workers_only && !worker.trusted) { |
| 154 | continue; | 154 | continue; |
| @@ -250,12 +250,10 @@ async function generateHorde(prompt, params, signal, reportProgress) { | |||
| 250 | console.log(generatedText); | 250 | console.log(generatedText); |
| 251 | console.log(`Generated by Horde Worker: ${WorkerName} [${WorkerModel}]`); | 251 | console.log(`Generated by Horde Worker: ${WorkerName} [${WorkerModel}]`); |
| 252 | return { text: generatedText, workerName: `Generated by Horde worker: ${WorkerName} [${WorkerModel}]` }; | 252 | return { text: generatedText, workerName: `Generated by Horde worker: ${WorkerName} [${WorkerModel}]` }; |
| 253 | } | 253 | } else if (!queue_position_first) { |
| 254 | else if (!queue_position_first) { | ||
| 255 | queue_position_first = statusCheckJson.queue_position; | 254 | queue_position_first = statusCheckJson.queue_position; |
| 256 | reportProgress && setGenerationProgress(0); | 255 | reportProgress && setGenerationProgress(0); |
| 257 | } | 256 | } else if (statusCheckJson.queue_position >= 0) { |
| 258 | else if (statusCheckJson.queue_position >= 0) { | ||
| 259 | let queue_position = statusCheckJson.queue_position; | 257 | let queue_position = statusCheckJson.queue_position; |
| 260 | const progress = Math.round(100 - (queue_position / queue_position_first * 100)); | 258 | const progress = Math.round(100 - (queue_position / queue_position_first * 100)); |
| 261 | reportProgress && setGenerationProgress(progress); | 259 | reportProgress && setGenerationProgress(progress); |
| @@ -268,17 +266,24 @@ async function generateHorde(prompt, params, signal, reportProgress) { | |||
| 268 | throw new Error('Horde timeout'); | 266 | throw new Error('Horde timeout'); |
| 269 | } | 267 | } |
| 270 | 268 | ||
| 269 | |||
| 271 | /** | 270 | /** |
| 272 | * Displays the available models in the Horde model selection dropdown. | 271 | * Displays the available models in the Horde model selection dropdown. |
| 273 | * @param {boolean} force Force refresh of the models | 272 | * @param {boolean} force Force refresh of the models |
| 274 | */ | 273 | */ |
| 275 | async function getHordeModels(force) { | 274 | async function getHordeModels(force) { |
| 275 | const sortByPerformance = (a, b) => b.performance - a.performance; | ||
| 276 | const sortByWhitelisted = (a, b) => b.is_whitelisted - a.is_whitelisted; | ||
| 277 | const sortByPopular = (a, b) => b.tags?.includes('popular') - a.tags?.includes('popular'); | ||
| 278 | |||
| 276 | $('#horde_model').empty(); | 279 | $('#horde_model').empty(); |
| 277 | models = (await getModels(force)).sort((a, b) => b.performance - a.performance); | 280 | models = (await getModels(force)).sort((a, b) => { |
| 281 | return sortByWhitelisted(a, b) || sortByPopular(a, b) || sortByPerformance(a, b); | ||
| 282 | }); | ||
| 278 | for (const model of models) { | 283 | for (const model of models) { |
| 279 | const option = document.createElement('option'); | 284 | const option = document.createElement('option'); |
| 280 | option.value = model.name; | 285 | option.value = model.name; |
| 281 | option.innerText = `${model.name} (ETA: ${model.eta}s, Speed: ${model.performance}, Queue: ${model.queued}, Workers: ${model.count})`; | 286 | option.innerText = hordeModelTextString(model); |
| 282 | option.selected = horde_settings.models.includes(model.name); | 287 | option.selected = horde_settings.models.includes(model.name); |
| 283 | $('#horde_model').append(option); | 288 | $('#horde_model').append(option); |
| 284 | } | 289 | } |
| @@ -323,8 +328,66 @@ async function showKudos() { | |||
| 323 | toastr.info(`Kudos: ${data.kudos}`, data.username); | 328 | toastr.info(`Kudos: ${data.kudos}`, data.username); |
| 324 | } | 329 | } |
| 325 | 330 | ||
| 331 | function hordeModelTextString(model) { | ||
| 332 | const q = hordeModelQueueStateString(model); | ||
| 333 | return `${model.name} (${q})`; | ||
| 334 | } | ||
| 335 | |||
| 336 | function hordeModelQueueStateString(model) { | ||
| 337 | return `ETA: ${model.eta}s, Speed: ${model.performance}, Queue: ${model.queued}, Workers: ${model.count}`; | ||
| 338 | } | ||
| 339 | |||
| 340 | function getHordeModelTemplate(option) { | ||
| 341 | const model = models.find(x => x.name === option?.element?.value); | ||
| 342 | |||
| 343 | if (!option.id || !model) { | ||
| 344 | console.debug('No model found for option', option, option?.element?.value); | ||
| 345 | console.debug('Models', models); | ||
| 346 | return option.text; | ||
| 347 | } | ||
| 348 | |||
| 349 | const strip = html => { | ||
| 350 | const tmp = document.createElement('DIV'); | ||
| 351 | tmp.innerHTML = html || ''; | ||
| 352 | return tmp.textContent || tmp.innerText || ''; | ||
| 353 | }; | ||
| 354 | |||
| 355 | // how much do we trust the metadata from the models repo? about this much | ||
| 356 | const displayName = strip(model.display_name || model.name).replace(/.*\//g, ''); | ||
| 357 | const description = strip(model.description); | ||
| 358 | const tags = model.tags ? model.tags.map(strip) : []; | ||
| 359 | const url = strip(model.url); | ||
| 360 | const style = strip(model.style); | ||
| 361 | |||
| 362 | const workerInfo = hordeModelQueueStateString(model); | ||
| 363 | const isPopular = model.tags?.includes('popular'); | ||
| 364 | const descriptionDiv = description ? `<div class="horde-model-description">${description}</div>` : ''; | ||
| 365 | const tagSpans = tags.length > 0 && | ||
| 366 | `${tags.map(tag => `<span class="tag tag_name">${tag}</span>`).join('')}</span>` || ''; | ||
| 367 | |||
| 368 | const modelDetailsLink = url && `<a href="${url}" target="_blank" rel="noopener noreferrer" class="model-details-link fa-solid fa-circle-question"> </a>`; | ||
| 369 | const capitalize = s => s ? s[0].toUpperCase() + s.slice(1) : ''; | ||
| 370 | const innerContent = [ | ||
| 371 | `<strong>${displayName}</strong> ${modelDetailsLink}`, | ||
| 372 | style ? `${capitalize(style)}` : '', | ||
| 373 | tagSpans ? `<span class="tags tags_inline inline-flex margin-r2">${tagSpans}</span>` : '', | ||
| 374 | ].filter(Boolean).join(' | '); | ||
| 375 | |||
| 376 | return $((` | ||
| 377 | <div class="flex-container flexFlowColumn"> | ||
| 378 | <div> | ||
| 379 | ${isPopular ? '<span class="fa-fw fa-solid fa-star" title="Popular"></span>' : ''} | ||
| 380 | ${innerContent} | ||
| 381 | </div> | ||
| 382 | ${descriptionDiv} | ||
| 383 | <div><small>${workerInfo}</small></div> | ||
| 384 | </div> | ||
| 385 | `)); | ||
| 386 | } | ||
| 387 | |||
| 326 | jQuery(function () { | 388 | jQuery(function () { |
| 327 | $('#horde_model').on('mousedown change', async function (e) { | 389 | $('#horde_model').on('mousedown change', async function (e) { |
| 390 | console.log('Horde model change', e); | ||
| 328 | horde_settings.models = $('#horde_model').val(); | 391 | horde_settings.models = $('#horde_model').val(); |
| 329 | console.log('Updated Horde models', horde_settings.models); | 392 | console.log('Updated Horde models', horde_settings.models); |
| 330 | 393 | ||
| @@ -374,10 +437,7 @@ jQuery(function () { | |||
| 374 | // Customize the pillbox text by shortening the full text | 437 | // Customize the pillbox text by shortening the full text |
| 375 | return data.id; | 438 | return data.id; |
| 376 | }, | 439 | }, |
| 377 | templateResult: function (data) { | 440 | templateResult: getHordeModelTemplate, |
| 378 | // Return the full text for the dropdown | ||
| 379 | return data.text; | ||
| 380 | }, | ||
| 381 | }); | 441 | }); |
| 382 | } | 442 | } |
| 383 | }); | 443 | }); |
| @@ -14,10 +14,15 @@ import { regexFromString, resetScrollHeight } from './utils.js'; | |||
| 14 | */ | 14 | */ |
| 15 | export let instruct_presets = []; | 15 | export let instruct_presets = []; |
| 16 | 16 | ||
| 17 | export const names_behavior_types = { | ||
| 18 | NONE: 'none', | ||
| 19 | FORCE: 'force', | ||
| 20 | ALWAYS: 'always', | ||
| 21 | }; | ||
| 22 | |||
| 17 | const controls = [ | 23 | const controls = [ |
| 18 | { id: 'instruct_enabled', property: 'enabled', isCheckbox: true }, | 24 | { id: 'instruct_enabled', property: 'enabled', isCheckbox: true }, |
| 19 | { id: 'instruct_wrap', property: 'wrap', isCheckbox: true }, | 25 | { id: 'instruct_wrap', property: 'wrap', isCheckbox: true }, |
| 20 | { id: 'instruct_system_prompt', property: 'system_prompt', isCheckbox: false }, | ||
| 21 | { id: 'instruct_system_sequence_prefix', property: 'system_sequence_prefix', isCheckbox: false }, | 26 | { id: 'instruct_system_sequence_prefix', property: 'system_sequence_prefix', isCheckbox: false }, |
| 22 | { id: 'instruct_system_sequence_suffix', property: 'system_sequence_suffix', isCheckbox: false }, | 27 | { id: 'instruct_system_sequence_suffix', property: 'system_sequence_suffix', isCheckbox: false }, |
| 23 | { id: 'instruct_input_sequence', property: 'input_sequence', isCheckbox: false }, | 28 | { id: 'instruct_input_sequence', property: 'input_sequence', isCheckbox: false }, |
| @@ -29,9 +34,6 @@ const controls = [ | |||
| 29 | { id: 'instruct_last_system_sequence', property: 'last_system_sequence', isCheckbox: false }, | 34 | { id: 'instruct_last_system_sequence', property: 'last_system_sequence', isCheckbox: false }, |
| 30 | { id: 'instruct_user_alignment_message', property: 'user_alignment_message', isCheckbox: false }, | 35 | { id: 'instruct_user_alignment_message', property: 'user_alignment_message', isCheckbox: false }, |
| 31 | { id: 'instruct_stop_sequence', property: 'stop_sequence', isCheckbox: false }, | 36 | { id: 'instruct_stop_sequence', property: 'stop_sequence', isCheckbox: false }, |
| 32 | { id: 'instruct_names', property: 'names', isCheckbox: true }, | ||
| 33 | { id: 'instruct_macro', property: 'macro', isCheckbox: true }, | ||
| 34 | { id: 'instruct_names_force_groups', property: 'names_force_groups', isCheckbox: true }, | ||
| 35 | { id: 'instruct_first_output_sequence', property: 'first_output_sequence', isCheckbox: false }, | 37 | { id: 'instruct_first_output_sequence', property: 'first_output_sequence', isCheckbox: false }, |
| 36 | { id: 'instruct_last_output_sequence', property: 'last_output_sequence', isCheckbox: false }, | 38 | { id: 'instruct_last_output_sequence', property: 'last_output_sequence', isCheckbox: false }, |
| 37 | { id: 'instruct_first_input_sequence', property: 'first_input_sequence', isCheckbox: false }, | 39 | { id: 'instruct_first_input_sequence', property: 'first_input_sequence', isCheckbox: false }, |
| @@ -39,6 +41,7 @@ const controls = [ | |||
| 39 | { id: 'instruct_activation_regex', property: 'activation_regex', isCheckbox: false }, | 41 | { id: 'instruct_activation_regex', property: 'activation_regex', isCheckbox: false }, |
| 40 | { id: 'instruct_bind_to_context', property: 'bind_to_context', isCheckbox: true }, | 42 | { id: 'instruct_bind_to_context', property: 'bind_to_context', isCheckbox: true }, |
| 41 | { id: 'instruct_skip_examples', property: 'skip_examples', isCheckbox: true }, | 43 | { id: 'instruct_skip_examples', property: 'skip_examples', isCheckbox: true }, |
| 44 | { id: 'instruct_names_behavior', property: 'names_behavior', isCheckbox: false }, | ||
| 42 | { id: 'instruct_system_same_as_user', property: 'system_same_as_user', isCheckbox: true, trigger: true }, | 45 | { id: 'instruct_system_same_as_user', property: 'system_same_as_user', isCheckbox: true, trigger: true }, |
| 43 | ]; | 46 | ]; |
| 44 | 47 | ||
| @@ -54,6 +57,15 @@ function migrateInstructModeSettings(settings) { | |||
| 54 | delete settings.separator_sequence; | 57 | delete settings.separator_sequence; |
| 55 | } | 58 | } |
| 56 | 59 | ||
| 60 | // names, names_force_groups => names_behavior | ||
| 61 | if (settings.names !== undefined) { | ||
| 62 | settings.names_behavior = settings.names | ||
| 63 | ? names_behavior_types.ALWAYS | ||
| 64 | : (settings.names_force_groups ? names_behavior_types.FORCE : names_behavior_types.NONE); | ||
| 65 | delete settings.names; | ||
| 66 | delete settings.names_force_groups; | ||
| 67 | } | ||
| 68 | |||
| 57 | const defaults = { | 69 | const defaults = { |
| 58 | input_suffix: '', | 70 | input_suffix: '', |
| 59 | system_sequence: '', | 71 | system_sequence: '', |
| @@ -65,6 +77,7 @@ function migrateInstructModeSettings(settings) { | |||
| 65 | names_force_groups: true, | 77 | names_force_groups: true, |
| 66 | skip_examples: false, | 78 | skip_examples: false, |
| 67 | system_same_as_user: false, | 79 | system_same_as_user: false, |
| 80 | names_behavior: names_behavior_types.FORCE, | ||
| 68 | }; | 81 | }; |
| 69 | 82 | ||
| 70 | for (let key in defaults) { | 83 | for (let key in defaults) { |
| @@ -94,6 +107,10 @@ export async function loadInstructMode(data) { | |||
| 94 | 107 | ||
| 95 | if (control.isCheckbox) { | 108 | if (control.isCheckbox) { |
| 96 | $element.prop('checked', power_user.instruct[control.property]); | 109 | $element.prop('checked', power_user.instruct[control.property]); |
| 110 | } else if ($element.is('select')) { | ||
| 111 | const value = power_user.instruct[control.property]; | ||
| 112 | $element.val(value); | ||
| 113 | $element.filter(`[value="${value}"]`).prop('checked', true); | ||
| 97 | } else { | 114 | } else { |
| 98 | $element.val(power_user.instruct[control.property]); | 115 | $element.val(power_user.instruct[control.property]); |
| 99 | } | 116 | } |
| @@ -119,12 +136,6 @@ export async function loadInstructMode(data) { | |||
| 119 | option.selected = name === power_user.instruct.preset; | 136 | option.selected = name === power_user.instruct.preset; |
| 120 | $('#instruct_presets').append(option); | 137 | $('#instruct_presets').append(option); |
| 121 | }); | 138 | }); |
| 122 | |||
| 123 | highlightDefaultPreset(); | ||
| 124 | } | ||
| 125 | |||
| 126 | function highlightDefaultPreset() { | ||
| 127 | $('#instruct_set_default').toggleClass('default', power_user.default_instruct === power_user.instruct.preset); | ||
| 128 | } | 139 | } |
| 129 | 140 | ||
| 130 | /** | 141 | /** |
| @@ -141,13 +152,6 @@ export function selectContextPreset(preset, { quiet = false, isAuto = false } = | |||
| 141 | !quiet && toastr.info(`Context Template: "${preset}" ${isAuto ? 'auto-' : ''}selected`); | 152 | !quiet && toastr.info(`Context Template: "${preset}" ${isAuto ? 'auto-' : ''}selected`); |
| 142 | } | 153 | } |
| 143 | 154 | ||
| 144 | // If instruct mode is disabled, enable it, except for default context template | ||
| 145 | if (!power_user.instruct.enabled && preset !== power_user.default_context) { | ||
| 146 | power_user.instruct.enabled = true; | ||
| 147 | $('#instruct_enabled').prop('checked', true).trigger('change'); | ||
| 148 | !quiet && toastr.info('Instruct Mode enabled'); | ||
| 149 | } | ||
| 150 | |||
| 151 | saveSettingsDebounced(); | 155 | saveSettingsDebounced(); |
| 152 | } | 156 | } |
| 153 | 157 | ||
| @@ -217,13 +221,6 @@ export function autoSelectInstructPreset(modelId) { | |||
| 217 | } | 221 | } |
| 218 | } | 222 | } |
| 219 | } | 223 | } |
| 220 | |||
| 221 | if (power_user.instruct.bind_to_context && power_user.default_instruct && power_user.instruct.preset !== power_user.default_instruct) { | ||
| 222 | if (instruct_presets.some(p => p.name === power_user.default_instruct)) { | ||
| 223 | console.log(`Instruct mode: default preset "${power_user.default_instruct}" selected`); | ||
| 224 | $('#instruct_presets').val(power_user.default_instruct).trigger('change'); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | 224 | } |
| 228 | 225 | ||
| 229 | return false; | 226 | return false; |
| @@ -311,9 +308,9 @@ export const force_output_sequence = { | |||
| 311 | * @returns {string} Formatted instruct mode chat message. | 308 | * @returns {string} Formatted instruct mode chat message. |
| 312 | */ | 309 | */ |
| 313 | export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2, forceOutputSequence) { | 310 | export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2, forceOutputSequence) { |
| 314 | let includeNames = isNarrator ? false : power_user.instruct.names; | 311 | let includeNames = isNarrator ? false : power_user.instruct.names_behavior === names_behavior_types.ALWAYS; |
| 315 | 312 | ||
| 316 | if (!isNarrator && power_user.instruct.names_force_groups && (selected_group || forceAvatar)) { | 313 | if (!isNarrator && power_user.instruct.names_behavior === names_behavior_types.FORCE && ((selected_group && name !== name1) || (forceAvatar && name !== name1))) { |
| 317 | includeNames = true; | 314 | includeNames = true; |
| 318 | } | 315 | } |
| 319 | 316 | ||
| @@ -416,7 +413,7 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) { | |||
| 416 | return mesExamplesArray.map(x => x.replace(/<START>\n/i, blockHeading)); | 413 | return mesExamplesArray.map(x => x.replace(/<START>\n/i, blockHeading)); |
| 417 | } | 414 | } |
| 418 | 415 | ||
| 419 | const includeNames = power_user.instruct.names || (!!selected_group && power_user.instruct.names_force_groups); | 416 | const includeNames = power_user.instruct.names_behavior === names_behavior_types.ALWAYS || (!!selected_group && power_user.instruct.names_behavior === names_behavior_types.FORCE); |
| 420 | 417 | ||
| 421 | let inputPrefix = power_user.instruct.input_sequence || ''; | 418 | let inputPrefix = power_user.instruct.input_sequence || ''; |
| 422 | let outputPrefix = power_user.instruct.output_sequence || ''; | 419 | let outputPrefix = power_user.instruct.output_sequence || ''; |
| @@ -460,7 +457,7 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) { | |||
| 460 | 457 | ||
| 461 | for (const example of blockExamples) { | 458 | for (const example of blockExamples) { |
| 462 | // If force group/persona names is set, we should override the include names for the user placeholder | 459 | // If force group/persona names is set, we should override the include names for the user placeholder |
| 463 | const includeThisName = includeNames || (power_user.instruct.names_force_groups && example.name == 'example_user'); | 460 | const includeThisName = includeNames || (power_user.instruct.names_behavior === names_behavior_types.FORCE && example.name == 'example_user'); |
| 464 | 461 | ||
| 465 | const prefix = example.name == 'example_user' ? inputPrefix : outputPrefix; | 462 | const prefix = example.name == 'example_user' ? inputPrefix : outputPrefix; |
| 466 | const suffix = example.name == 'example_user' ? inputSuffix : outputSuffix; | 463 | const suffix = example.name == 'example_user' ? inputSuffix : outputSuffix; |
| @@ -490,7 +487,7 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) { | |||
| 490 | * @returns {string} Formatted instruct mode last prompt line. | 487 | * @returns {string} Formatted instruct mode last prompt line. |
| 491 | */ | 488 | */ |
| 492 | export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2, isQuiet, isQuietToLoud) { | 489 | export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2, isQuiet, isQuietToLoud) { |
| 493 | const includeNames = name && (power_user.instruct.names || (!!selected_group && power_user.instruct.names_force_groups)) && !(isQuiet && !isQuietToLoud); | 490 | const includeNames = name && (power_user.instruct.names_behavior === names_behavior_types.ALWAYS || (!!selected_group && power_user.instruct.names_behavior === names_behavior_types.FORCE)) && !(isQuiet && !isQuietToLoud); |
| 494 | 491 | ||
| 495 | function getSequence() { | 492 | function getSequence() { |
| 496 | // User impersonation prompt | 493 | // User impersonation prompt |
| @@ -514,6 +511,19 @@ export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, | |||
| 514 | } | 511 | } |
| 515 | 512 | ||
| 516 | let sequence = getSequence() || ''; | 513 | let sequence = getSequence() || ''; |
| 514 | let nameFiller = ''; | ||
| 515 | |||
| 516 | // A hack for Mistral's formatting that has a normal output sequence ending with a space | ||
| 517 | if ( | ||
| 518 | includeNames && | ||
| 519 | power_user.instruct.last_output_sequence && | ||
| 520 | power_user.instruct.output_sequence && | ||
| 521 | sequence === power_user.instruct.last_output_sequence && | ||
| 522 | /\s$/.test(power_user.instruct.output_sequence) && | ||
| 523 | !/\s$/.test(power_user.instruct.last_output_sequence) | ||
| 524 | ) { | ||
| 525 | nameFiller = power_user.instruct.output_sequence.slice(-1); | ||
| 526 | } | ||
| 517 | 527 | ||
| 518 | if (power_user.instruct.macro) { | 528 | if (power_user.instruct.macro) { |
| 519 | sequence = substituteParams(sequence, name1, name2); | 529 | sequence = substituteParams(sequence, name1, name2); |
| @@ -521,7 +531,7 @@ export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, | |||
| 521 | } | 531 | } |
| 522 | 532 | ||
| 523 | const separator = power_user.instruct.wrap ? '\n' : ''; | 533 | const separator = power_user.instruct.wrap ? '\n' : ''; |
| 524 | let text = includeNames ? (separator + sequence + separator + `${name}:`) : (separator + sequence); | 534 | let text = includeNames ? (separator + sequence + separator + nameFiller + `${name}:`) : (separator + sequence); |
| 525 | 535 | ||
| 526 | // Quiet prompt already has a newline at the end | 536 | // Quiet prompt already has a newline at the end |
| 527 | if (isQuiet && separator) { | 537 | if (isQuiet && separator) { |
| @@ -549,10 +559,6 @@ function selectMatchingContextTemplate(name) { | |||
| 549 | break; | 559 | break; |
| 550 | } | 560 | } |
| 551 | } | 561 | } |
| 552 | if (!foundMatch) { | ||
| 553 | // If no match was found, select default context preset | ||
| 554 | selectContextPreset(power_user.default_context, { isAuto: true }); | ||
| 555 | } | ||
| 556 | } | 562 | } |
| 557 | 563 | ||
| 558 | /** | 564 | /** |
| @@ -566,9 +572,13 @@ export function replaceInstructMacros(input, env) { | |||
| 566 | if (!input) { | 572 | if (!input) { |
| 567 | return ''; | 573 | return ''; |
| 568 | } | 574 | } |
| 575 | |||
| 576 | const syspromptMacros = { | ||
| 577 | 'systemPrompt': (power_user.prefer_character_prompt && env.charPrompt ? env.charPrompt : power_user.sysprompt.content), | ||
| 578 | 'defaultSystemPrompt|instructSystem|instructSystemPrompt': power_user.sysprompt.content, | ||
| 579 | }; | ||
| 580 | |||
| 569 | const instructMacros = { | 581 | const instructMacros = { |
| 570 | 'systemPrompt': (power_user.prefer_character_prompt && env.charPrompt ? env.charPrompt : power_user.instruct.system_prompt), | ||
| 571 | 'instructSystem|instructSystemPrompt': power_user.instruct.system_prompt, | ||
| 572 | 'instructSystemPromptPrefix': power_user.instruct.system_sequence_prefix, | 582 | 'instructSystemPromptPrefix': power_user.instruct.system_sequence_prefix, |
| 573 | 'instructSystemPromptSuffix': power_user.instruct.system_sequence_suffix, | 583 | 'instructSystemPromptSuffix': power_user.instruct.system_sequence_suffix, |
| 574 | 'instructInput|instructUserPrefix': power_user.instruct.input_sequence, | 584 | 'instructInput|instructUserPrefix': power_user.instruct.input_sequence, |
| @@ -591,6 +601,11 @@ export function replaceInstructMacros(input, env) { | |||
| 591 | input = input.replace(regex, power_user.instruct.enabled ? value : ''); | 601 | input = input.replace(regex, power_user.instruct.enabled ? value : ''); |
| 592 | } | 602 | } |
| 593 | 603 | ||
| 604 | for (const [placeholder, value] of Object.entries(syspromptMacros)) { | ||
| 605 | const regex = new RegExp(`{{(${placeholder})}}`, 'gi'); | ||
| 606 | input = input.replace(regex, power_user.sysprompt.enabled ? value : ''); | ||
| 607 | } | ||
| 608 | |||
| 594 | input = input.replace(/{{exampleSeparator}}/gi, power_user.context.example_separator); | 609 | input = input.replace(/{{exampleSeparator}}/gi, power_user.context.example_separator); |
| 595 | input = input.replace(/{{chatStart}}/gi, power_user.context.chat_start); | 610 | input = input.replace(/{{chatStart}}/gi, power_user.context.chat_start); |
| 596 | 611 | ||
| @@ -598,20 +613,6 @@ export function replaceInstructMacros(input, env) { | |||
| 598 | } | 613 | } |
| 599 | 614 | ||
| 600 | jQuery(() => { | 615 | jQuery(() => { |
| 601 | $('#instruct_set_default').on('click', function () { | ||
| 602 | if (power_user.instruct.preset === power_user.default_instruct) { | ||
| 603 | power_user.default_instruct = null; | ||
| 604 | $(this).removeClass('default'); | ||
| 605 | toastr.info('Default instruct template cleared'); | ||
| 606 | } else { | ||
| 607 | power_user.default_instruct = power_user.instruct.preset; | ||
| 608 | $(this).addClass('default'); | ||
| 609 | toastr.info(`Default instruct template set to ${power_user.default_instruct}`); | ||
| 610 | } | ||
| 611 | |||
| 612 | saveSettingsDebounced(); | ||
| 613 | }); | ||
| 614 | |||
| 615 | $('#instruct_system_same_as_user').on('input', function () { | 616 | $('#instruct_system_same_as_user').on('input', function () { |
| 616 | const state = !!$(this).prop('checked'); | 617 | const state = !!$(this).prop('checked'); |
| 617 | if (state) { | 618 | if (state) { |
| @@ -640,9 +641,6 @@ jQuery(() => { | |||
| 640 | // When instruct mode gets enabled, select context template matching selected instruct preset | 641 | // When instruct mode gets enabled, select context template matching selected instruct preset |
| 641 | if (power_user.instruct.enabled) { | 642 | if (power_user.instruct.enabled) { |
| 642 | selectMatchingContextTemplate(power_user.instruct.preset); | 643 | selectMatchingContextTemplate(power_user.instruct.preset); |
| 643 | } else { | ||
| 644 | // When instruct mode gets disabled, select default context preset | ||
| 645 | selectContextPreset(power_user.default_context); | ||
| 646 | } | 644 | } |
| 647 | }); | 645 | }); |
| 648 | 646 | ||
| @@ -668,6 +666,10 @@ jQuery(() => { | |||
| 668 | 666 | ||
| 669 | if (control.isCheckbox) { | 667 | if (control.isCheckbox) { |
| 670 | $element.prop('checked', power_user.instruct[control.property]).trigger('input'); | 668 | $element.prop('checked', power_user.instruct[control.property]).trigger('input'); |
| 669 | } else if ($element.is('select')) { | ||
| 670 | const value = power_user.instruct[control.property]; | ||
| 671 | $element.val(value); | ||
| 672 | $element.filter(`[value="${value}"]`).prop('checked', true).trigger('input'); | ||
| 671 | } else { | 673 | } else { |
| 672 | $element.val(power_user.instruct[control.property]); | 674 | $element.val(power_user.instruct[control.property]); |
| 673 | $element.trigger('input'); | 675 | $element.trigger('input'); |
| @@ -679,7 +681,13 @@ jQuery(() => { | |||
| 679 | // Select matching context template | 681 | // Select matching context template |
| 680 | selectMatchingContextTemplate(name); | 682 | selectMatchingContextTemplate(name); |
| 681 | } | 683 | } |
| 682 | |||
| 683 | highlightDefaultPreset(); | ||
| 684 | }); | 684 | }); |
| 685 | |||
| 686 | if (!CSS.supports('field-sizing', 'content')) { | ||
| 687 | $('#InstructSequencesColumn details').on('toggle', function () { | ||
| 688 | if ($(this).prop('open')) { | ||
| 689 | resetScrollHeight($(this).find('textarea')); | ||
| 690 | } | ||
| 691 | }); | ||
| 692 | } | ||
| 685 | }); | 693 | }); |
| @@ -5,9 +5,7 @@ import { | |||
| 5 | novelai_setting_names, | 5 | novelai_setting_names, |
| 6 | saveSettingsDebounced, | 6 | saveSettingsDebounced, |
| 7 | setGenerationParamsFromPreset, | 7 | setGenerationParamsFromPreset, |
| 8 | substituteParams, | ||
| 9 | } from '../script.js'; | 8 | } from '../script.js'; |
| 10 | import { getCfgPrompt } from './cfg-scale.js'; | ||
| 11 | import { MAX_CONTEXT_DEFAULT, MAX_RESPONSE_DEFAULT, power_user } from './power-user.js'; | 9 | import { MAX_CONTEXT_DEFAULT, MAX_RESPONSE_DEFAULT, power_user } from './power-user.js'; |
| 12 | import { getTextTokens, tokenizers } from './tokenizers.js'; | 10 | import { getTextTokens, tokenizers } from './tokenizers.js'; |
| 13 | import { getEventSourceStream } from './sse-stream.js'; | 11 | import { getEventSourceStream } from './sse-stream.js'; |
| @@ -24,6 +22,7 @@ const maximum_output_length = 150; | |||
| 24 | const default_presets = { | 22 | const default_presets = { |
| 25 | 'clio-v1': 'Talker-Chat-Clio', | 23 | 'clio-v1': 'Talker-Chat-Clio', |
| 26 | 'kayra-v1': 'Carefree-Kayra', | 24 | 'kayra-v1': 'Carefree-Kayra', |
| 25 | 'llama-3-erato-v1': 'Erato-Dragonfruit', | ||
| 27 | }; | 26 | }; |
| 28 | 27 | ||
| 29 | export const nai_settings = { | 28 | export const nai_settings = { |
| @@ -38,13 +37,16 @@ export const nai_settings = { | |||
| 38 | top_p: 0.75, | 37 | top_p: 0.75, |
| 39 | top_a: 0.08, | 38 | top_a: 0.08, |
| 40 | typical_p: 0.975, | 39 | typical_p: 0.975, |
| 40 | min_p: 0, | ||
| 41 | math1_temp: 1, | ||
| 42 | math1_quad: 0, | ||
| 43 | math1_quad_entropy_scale: 0, | ||
| 41 | min_length: 1, | 44 | min_length: 1, |
| 42 | model_novel: 'clio-v1', | 45 | model_novel: 'clio-v1', |
| 43 | preset_settings_novel: 'Talker-Chat-Clio', | 46 | preset_settings_novel: 'Talker-Chat-Clio', |
| 44 | streaming_novel: false, | 47 | streaming_novel: false, |
| 45 | preamble: default_preamble, | 48 | preamble: default_preamble, |
| 46 | prefix: '', | 49 | prefix: '', |
| 47 | cfg_uc: '', | ||
| 48 | banned_tokens: '', | 50 | banned_tokens: '', |
| 49 | order: default_order, | 51 | order: default_order, |
| 50 | logit_bias: [], | 52 | logit_bias: [], |
| @@ -57,6 +59,19 @@ const nai_tiers = { | |||
| 57 | 3: 'Opus', | 59 | 3: 'Opus', |
| 58 | }; | 60 | }; |
| 59 | 61 | ||
| 62 | const samplers = { | ||
| 63 | temperature: 0, | ||
| 64 | top_k: 1, | ||
| 65 | top_p: 2, | ||
| 66 | tfs: 3, | ||
| 67 | top_a: 4, | ||
| 68 | typical_p: 5, | ||
| 69 | // removed samplers were here | ||
| 70 | mirostat: 8, | ||
| 71 | math1: 9, | ||
| 72 | min_p: 10, | ||
| 73 | }; | ||
| 74 | |||
| 60 | let novel_data = null; | 75 | let novel_data = null; |
| 61 | let badWordsCache = {}; | 76 | let badWordsCache = {}; |
| 62 | const BIAS_KEY = '#novel_api-settings'; | 77 | const BIAS_KEY = '#novel_api-settings'; |
| @@ -91,6 +106,37 @@ export function getKayraMaxResponseTokens() { | |||
| 91 | return maximum_output_length; | 106 | return maximum_output_length; |
| 92 | } | 107 | } |
| 93 | 108 | ||
| 109 | export function convertNovelPreset(data) { | ||
| 110 | if (!data || typeof data !== 'object' || data.presetVersion !== 3 || !data.parameters || typeof data.parameters !== 'object') { | ||
| 111 | return data; | ||
| 112 | } | ||
| 113 | |||
| 114 | return { | ||
| 115 | max_context: 8000, | ||
| 116 | temperature: data.parameters.temperature, | ||
| 117 | max_length: data.parameters.max_length, | ||
| 118 | min_length: data.parameters.min_length, | ||
| 119 | top_k: data.parameters.top_k, | ||
| 120 | top_p: data.parameters.top_p, | ||
| 121 | top_a: data.parameters.top_a, | ||
| 122 | typical_p: data.parameters.typical_p, | ||
| 123 | tail_free_sampling: data.parameters.tail_free_sampling, | ||
| 124 | repetition_penalty: data.parameters.repetition_penalty, | ||
| 125 | repetition_penalty_range: data.parameters.repetition_penalty_range, | ||
| 126 | repetition_penalty_slope: data.parameters.repetition_penalty_slope, | ||
| 127 | repetition_penalty_frequency: data.parameters.repetition_penalty_frequency, | ||
| 128 | repetition_penalty_presence: data.parameters.repetition_penalty_presence, | ||
| 129 | phrase_rep_pen: data.parameters.phrase_rep_pen, | ||
| 130 | mirostat_lr: data.parameters.mirostat_lr, | ||
| 131 | mirostat_tau: data.parameters.mirostat_tau, | ||
| 132 | math1_temp: data.parameters.math1_temp, | ||
| 133 | math1_quad: data.parameters.math1_quad, | ||
| 134 | math1_quad_entropy_scale: data.parameters.math1_quad_entropy_scale, | ||
| 135 | min_p: data.parameters.min_p, | ||
| 136 | order: Array.isArray(data.parameters.order) ? data.parameters.order.filter(s => s.enabled && Object.keys(samplers).includes(s.id)).map(s => samplers[s.id]) : default_order, | ||
| 137 | }; | ||
| 138 | } | ||
| 139 | |||
| 94 | export function getNovelTier() { | 140 | export function getNovelTier() { |
| 95 | return nai_tiers[novel_data?.tier] ?? 'no_connection'; | 141 | return nai_tiers[novel_data?.tier] ?? 'no_connection'; |
| 96 | } | 142 | } |
| @@ -141,16 +187,18 @@ export function loadNovelPreset(preset) { | |||
| 141 | nai_settings.top_a = preset.top_a; | 187 | nai_settings.top_a = preset.top_a; |
| 142 | nai_settings.typical_p = preset.typical_p; | 188 | nai_settings.typical_p = preset.typical_p; |
| 143 | nai_settings.min_length = preset.min_length; | 189 | nai_settings.min_length = preset.min_length; |
| 144 | nai_settings.cfg_scale = preset.cfg_scale; | ||
| 145 | nai_settings.phrase_rep_pen = preset.phrase_rep_pen; | 190 | nai_settings.phrase_rep_pen = preset.phrase_rep_pen; |
| 146 | nai_settings.mirostat_lr = preset.mirostat_lr; | 191 | nai_settings.mirostat_lr = preset.mirostat_lr; |
| 147 | nai_settings.mirostat_tau = preset.mirostat_tau; | 192 | nai_settings.mirostat_tau = preset.mirostat_tau; |
| 148 | nai_settings.prefix = preset.prefix; | 193 | nai_settings.prefix = preset.prefix; |
| 149 | nai_settings.cfg_uc = preset.cfg_uc || ''; | ||
| 150 | nai_settings.banned_tokens = preset.banned_tokens || ''; | 194 | nai_settings.banned_tokens = preset.banned_tokens || ''; |
| 151 | nai_settings.order = preset.order || default_order; | 195 | nai_settings.order = preset.order || default_order; |
| 152 | nai_settings.logit_bias = preset.logit_bias || []; | 196 | nai_settings.logit_bias = preset.logit_bias || []; |
| 153 | nai_settings.preamble = preset.preamble || default_preamble; | 197 | nai_settings.preamble = preset.preamble || default_preamble; |
| 198 | nai_settings.min_p = preset.min_p || 0; | ||
| 199 | nai_settings.math1_temp = preset.math1_temp || 1; | ||
| 200 | nai_settings.math1_quad = preset.math1_quad || 0; | ||
| 201 | nai_settings.math1_quad_entropy_scale = preset.math1_quad_entropy_scale || 0; | ||
| 154 | loadNovelSettingsUi(nai_settings); | 202 | loadNovelSettingsUi(nai_settings); |
| 155 | } | 203 | } |
| 156 | 204 | ||
| @@ -178,16 +226,18 @@ export function loadNovelSettings(settings) { | |||
| 178 | nai_settings.typical_p = settings.typical_p; | 226 | nai_settings.typical_p = settings.typical_p; |
| 179 | nai_settings.min_length = settings.min_length; | 227 | nai_settings.min_length = settings.min_length; |
| 180 | nai_settings.phrase_rep_pen = settings.phrase_rep_pen; | 228 | nai_settings.phrase_rep_pen = settings.phrase_rep_pen; |
| 181 | nai_settings.cfg_scale = settings.cfg_scale; | ||
| 182 | nai_settings.mirostat_lr = settings.mirostat_lr; | 229 | nai_settings.mirostat_lr = settings.mirostat_lr; |
| 183 | nai_settings.mirostat_tau = settings.mirostat_tau; | 230 | nai_settings.mirostat_tau = settings.mirostat_tau; |
| 184 | nai_settings.streaming_novel = !!settings.streaming_novel; | 231 | nai_settings.streaming_novel = !!settings.streaming_novel; |
| 185 | nai_settings.preamble = settings.preamble || default_preamble; | 232 | nai_settings.preamble = settings.preamble || default_preamble; |
| 186 | nai_settings.prefix = settings.prefix; | 233 | nai_settings.prefix = settings.prefix; |
| 187 | nai_settings.cfg_uc = settings.cfg_uc || ''; | ||
| 188 | nai_settings.banned_tokens = settings.banned_tokens || ''; | 234 | nai_settings.banned_tokens = settings.banned_tokens || ''; |
| 189 | nai_settings.order = settings.order || default_order; | 235 | nai_settings.order = settings.order || default_order; |
| 190 | nai_settings.logit_bias = settings.logit_bias || []; | 236 | nai_settings.logit_bias = settings.logit_bias || []; |
| 237 | nai_settings.min_p = settings.min_p || 0; | ||
| 238 | nai_settings.math1_temp = settings.math1_temp || 1; | ||
| 239 | nai_settings.math1_quad = settings.math1_quad || 0; | ||
| 240 | nai_settings.math1_quad_entropy_scale = settings.math1_quad_entropy_scale || 0; | ||
| 191 | loadNovelSettingsUi(nai_settings); | 241 | loadNovelSettingsUi(nai_settings); |
| 192 | } | 242 | } |
| 193 | 243 | ||
| @@ -214,8 +264,6 @@ function loadNovelSettingsUi(ui_settings) { | |||
| 214 | $('#top_a_counter_novel').val(Number(ui_settings.top_a).toFixed(3)); | 264 | $('#top_a_counter_novel').val(Number(ui_settings.top_a).toFixed(3)); |
| 215 | $('#typical_p_novel').val(ui_settings.typical_p); | 265 | $('#typical_p_novel').val(ui_settings.typical_p); |
| 216 | $('#typical_p_counter_novel').val(Number(ui_settings.typical_p).toFixed(3)); | 266 | $('#typical_p_counter_novel').val(Number(ui_settings.typical_p).toFixed(3)); |
| 217 | $('#cfg_scale_novel').val(ui_settings.cfg_scale); | ||
| 218 | $('#cfg_scale_counter_novel').val(Number(ui_settings.cfg_scale).toFixed(2)); | ||
| 219 | $('#phrase_rep_pen_novel').val(ui_settings.phrase_rep_pen || 'off'); | 267 | $('#phrase_rep_pen_novel').val(ui_settings.phrase_rep_pen || 'off'); |
| 220 | $('#mirostat_lr_novel').val(ui_settings.mirostat_lr); | 268 | $('#mirostat_lr_novel').val(ui_settings.mirostat_lr); |
| 221 | $('#mirostat_lr_counter_novel').val(Number(ui_settings.mirostat_lr).toFixed(2)); | 269 | $('#mirostat_lr_counter_novel').val(Number(ui_settings.mirostat_lr).toFixed(2)); |
| @@ -225,8 +273,15 @@ function loadNovelSettingsUi(ui_settings) { | |||
| 225 | $('#min_length_counter_novel').val(Number(ui_settings.min_length).toFixed(0)); | 273 | $('#min_length_counter_novel').val(Number(ui_settings.min_length).toFixed(0)); |
| 226 | $('#nai_preamble_textarea').val(ui_settings.preamble); | 274 | $('#nai_preamble_textarea').val(ui_settings.preamble); |
| 227 | $('#nai_prefix').val(ui_settings.prefix || 'vanilla'); | 275 | $('#nai_prefix').val(ui_settings.prefix || 'vanilla'); |
| 228 | $('#nai_cfg_uc').val(ui_settings.cfg_uc || ''); | ||
| 229 | $('#nai_banned_tokens').val(ui_settings.banned_tokens || ''); | 276 | $('#nai_banned_tokens').val(ui_settings.banned_tokens || ''); |
| 277 | $('#min_p_novel').val(ui_settings.min_p); | ||
| 278 | $('#min_p_counter_novel').val(Number(ui_settings.min_p).toFixed(3)); | ||
| 279 | $('#math1_temp_novel').val(ui_settings.math1_temp); | ||
| 280 | $('#math1_temp_counter_novel').val(Number(ui_settings.math1_temp).toFixed(2)); | ||
| 281 | $('#math1_quad_novel').val(ui_settings.math1_quad); | ||
| 282 | $('#math1_quad_counter_novel').val(Number(ui_settings.math1_quad).toFixed(2)); | ||
| 283 | $('#math1_quad_entropy_scale_novel').val(ui_settings.math1_quad_entropy_scale); | ||
| 284 | $('#math1_quad_entropy_scale_counter_novel').val(Number(ui_settings.math1_quad_entropy_scale).toFixed(2)); | ||
| 230 | 285 | ||
| 231 | $('#streaming_novel').prop('checked', ui_settings.streaming_novel); | 286 | $('#streaming_novel').prop('checked', ui_settings.streaming_novel); |
| 232 | sortItemsByOrder(ui_settings.order); | 287 | sortItemsByOrder(ui_settings.order); |
| @@ -313,29 +368,41 @@ const sliders = [ | |||
| 313 | setValue: (val) => { nai_settings.mirostat_lr = Number(val).toFixed(2); }, | 368 | setValue: (val) => { nai_settings.mirostat_lr = Number(val).toFixed(2); }, |
| 314 | }, | 369 | }, |
| 315 | { | 370 | { |
| 316 | sliderId: '#cfg_scale_novel', | ||
| 317 | counterId: '#cfg_scale_counter_novel', | ||
| 318 | format: (val) => `${val}`, | ||
| 319 | setValue: (val) => { nai_settings.cfg_scale = Number(val).toFixed(2); }, | ||
| 320 | }, | ||
| 321 | { | ||
| 322 | sliderId: '#min_length_novel', | 371 | sliderId: '#min_length_novel', |
| 323 | counterId: '#min_length_counter_novel', | 372 | counterId: '#min_length_counter_novel', |
| 324 | format: (val) => `${val}`, | 373 | format: (val) => `${val}`, |
| 325 | setValue: (val) => { nai_settings.min_length = Number(val).toFixed(0); }, | 374 | setValue: (val) => { nai_settings.min_length = Number(val).toFixed(0); }, |
| 326 | }, | 375 | }, |
| 327 | { | 376 | { |
| 328 | sliderId: '#nai_cfg_uc', | ||
| 329 | counterId: '#nai_cfg_uc_counter', | ||
| 330 | format: (val) => val, | ||
| 331 | setValue: (val) => { nai_settings.cfg_uc = val; }, | ||
| 332 | }, | ||
| 333 | { | ||
| 334 | sliderId: '#nai_banned_tokens', | 377 | sliderId: '#nai_banned_tokens', |
| 335 | counterId: '#nai_banned_tokens_counter', | 378 | counterId: '#nai_banned_tokens_counter', |
| 336 | format: (val) => val, | 379 | format: (val) => val, |
| 337 | setValue: (val) => { nai_settings.banned_tokens = val; }, | 380 | setValue: (val) => { nai_settings.banned_tokens = val; }, |
| 338 | }, | 381 | }, |
| 382 | { | ||
| 383 | sliderId: '#min_p_novel', | ||
| 384 | counterId: '#min_p_counter_novel', | ||
| 385 | format: (val) => Number(val).toFixed(3), | ||
| 386 | setValue: (val) => { nai_settings.min_p = Number(val); }, | ||
| 387 | }, | ||
| 388 | { | ||
| 389 | sliderId: '#math1_temp_novel', | ||
| 390 | counterId: '#math1_temp_counter_novel', | ||
| 391 | format: (val) => Number(val).toFixed(2), | ||
| 392 | setValue: (val) => { nai_settings.math1_temp = Number(val); }, | ||
| 393 | }, | ||
| 394 | { | ||
| 395 | sliderId: '#math1_quad_novel', | ||
| 396 | counterId: '#math1_quad_counter_novel', | ||
| 397 | format: (val) => Number(val).toFixed(2), | ||
| 398 | setValue: (val) => { nai_settings.math1_quad = Number(val); }, | ||
| 399 | }, | ||
| 400 | { | ||
| 401 | sliderId: '#math1_quad_entropy_scale_novel', | ||
| 402 | counterId: '#math1_quad_entropy_scale_counter_novel', | ||
| 403 | format: (val) => Number(val).toFixed(2), | ||
| 404 | setValue: (val) => { nai_settings.math1_quad_entropy_scale = Number(val); }, | ||
| 405 | }, | ||
| 339 | ]; | 406 | ]; |
| 340 | 407 | ||
| 341 | function getBadWordIds(banned_tokens, tokenizerType) { | 408 | function getBadWordIds(banned_tokens, tokenizerType) { |
| @@ -423,11 +490,8 @@ function getBadWordPermutations(text) { | |||
| 423 | return result.filter(onlyUnique); | 490 | return result.filter(onlyUnique); |
| 424 | } | 491 | } |
| 425 | 492 | ||
| 426 | export function getNovelGenerationData(finalPrompt, settings, maxLength, isImpersonate, isContinue, cfgValues, type) { | 493 | export function getNovelGenerationData(finalPrompt, settings, maxLength, isImpersonate, isContinue, _cfgValues, type) { |
| 427 | console.debug('NovelAI generation data for', type); | 494 | console.debug('NovelAI generation data for', type); |
| 428 | if (cfgValues && cfgValues.guidanceScale && cfgValues.guidanceScale?.value !== 1) { | ||
| 429 | cfgValues.negativePrompt = (getCfgPrompt(cfgValues.guidanceScale, true))?.value; | ||
| 430 | } | ||
| 431 | 495 | ||
| 432 | const tokenizerType = getTokenizerTypeForModel(nai_settings.model_novel); | 496 | const tokenizerType = getTokenizerTypeForModel(nai_settings.model_novel); |
| 433 | const stopSequences = (tokenizerType !== tokenizers.NONE) | 497 | const stopSequences = (tokenizerType !== tokenizers.NONE) |
| @@ -451,7 +515,14 @@ export function getNovelGenerationData(finalPrompt, settings, maxLength, isImper | |||
| 451 | console.log(finalPrompt); | 515 | console.log(finalPrompt); |
| 452 | } | 516 | } |
| 453 | 517 | ||
| 454 | const adjustedMaxLength = nai_settings.model_novel.includes('kayra') ? getKayraMaxResponseTokens() : maximum_output_length; | 518 | const isKayra = nai_settings.model_novel.includes('kayra'); |
| 519 | const isErato = nai_settings.model_novel.includes('erato'); | ||
| 520 | |||
| 521 | if (isErato) { | ||
| 522 | finalPrompt = '<|startoftext|>' + finalPrompt; | ||
| 523 | } | ||
| 524 | |||
| 525 | const adjustedMaxLength = (isKayra || isErato) ? getKayraMaxResponseTokens() : maximum_output_length; | ||
| 455 | 526 | ||
| 456 | return { | 527 | return { |
| 457 | 'input': finalPrompt, | 528 | 'input': finalPrompt, |
| @@ -469,11 +540,13 @@ export function getNovelGenerationData(finalPrompt, settings, maxLength, isImper | |||
| 469 | 'top_a': Number(nai_settings.top_a), | 540 | 'top_a': Number(nai_settings.top_a), |
| 470 | 'top_p': Number(nai_settings.top_p), | 541 | 'top_p': Number(nai_settings.top_p), |
| 471 | 'top_k': Number(nai_settings.top_k), | 542 | 'top_k': Number(nai_settings.top_k), |
| 543 | 'min_p': Number(nai_settings.min_p), | ||
| 544 | 'math1_temp': Number(nai_settings.math1_temp), | ||
| 545 | 'math1_quad': Number(nai_settings.math1_quad), | ||
| 546 | 'math1_quad_entropy_scale': Number(nai_settings.math1_quad_entropy_scale), | ||
| 472 | 'typical_p': Number(nai_settings.typical_p), | 547 | 'typical_p': Number(nai_settings.typical_p), |
| 473 | 'mirostat_lr': Number(nai_settings.mirostat_lr), | 548 | 'mirostat_lr': Number(nai_settings.mirostat_lr), |
| 474 | 'mirostat_tau': Number(nai_settings.mirostat_tau), | 549 | 'mirostat_tau': Number(nai_settings.mirostat_tau), |
| 475 | 'cfg_scale': cfgValues?.guidanceScale?.value ?? Number(nai_settings.cfg_scale), | ||
| 476 | 'cfg_uc': cfgValues?.negativePrompt ?? substituteParams(nai_settings.cfg_uc) ?? '', | ||
| 477 | 'phrase_rep_pen': nai_settings.phrase_rep_pen, | 550 | 'phrase_rep_pen': nai_settings.phrase_rep_pen, |
| 478 | 'stop_sequences': stopSequences, | 551 | 'stop_sequences': stopSequences, |
| 479 | 'bad_words_ids': badWordIds, | 552 | 'bad_words_ids': badWordIds, |
| @@ -492,7 +565,8 @@ function selectPrefix(selected_prefix, finalPrompt) { | |||
| 492 | let useInstruct = false; | 565 | let useInstruct = false; |
| 493 | const clio = nai_settings.model_novel.includes('clio'); | 566 | const clio = nai_settings.model_novel.includes('clio'); |
| 494 | const kayra = nai_settings.model_novel.includes('kayra'); | 567 | const kayra = nai_settings.model_novel.includes('kayra'); |
| 495 | const isNewModel = clio || kayra; | 568 | const erato = nai_settings.model_novel.includes('erato'); |
| 569 | const isNewModel = clio || kayra || erato; | ||
| 496 | 570 | ||
| 497 | if (isNewModel) { | 571 | if (isNewModel) { |
| 498 | // NovelAI claims they scan backwards 1000 characters (not tokens!) to look for instruct brackets. That's really short. | 572 | // NovelAI claims they scan backwards 1000 characters (not tokens!) to look for instruct brackets. That's really short. |
| @@ -511,6 +585,9 @@ function getTokenizerTypeForModel(model) { | |||
| 511 | if (model.includes('kayra')) { | 585 | if (model.includes('kayra')) { |
| 512 | return tokenizers.NERD2; | 586 | return tokenizers.NERD2; |
| 513 | } | 587 | } |
| 588 | if (model.includes('erato')) { | ||
| 589 | return tokenizers.LLAMA3; | ||
| 590 | } | ||
| 514 | return tokenizers.NONE; | 591 | return tokenizers.NONE; |
| 515 | } | 592 | } |
| 516 | 593 | ||
| @@ -431,7 +431,7 @@ function setOpenAIMessages(chat) { | |||
| 431 | case character_names_behavior.NONE: | 431 | case character_names_behavior.NONE: |
| 432 | break; | 432 | break; |
| 433 | case character_names_behavior.DEFAULT: | 433 | case character_names_behavior.DEFAULT: |
| 434 | if (selected_group || (chat[j].force_avatar && chat[j].name !== name1 && chat[j].extra?.type !== system_message_types.NARRATOR)) { | 434 | if ((selected_group && chat[j].name !== name1) || (chat[j].force_avatar && chat[j].name !== name1 && chat[j].extra?.type !== system_message_types.NARRATOR)) { |
| 435 | content = `${chat[j].name}: ${content}`; | 435 | content = `${chat[j].name}: ${content}`; |
| 436 | } | 436 | } |
| 437 | break; | 437 | break; |
| @@ -855,6 +855,12 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 855 | } | 855 | } |
| 856 | 856 | ||
| 857 | const prompt = prompts.get(source); | 857 | const prompt = prompts.get(source); |
| 858 | |||
| 859 | if (prompt.injection_position === INJECTION_POSITION.ABSOLUTE) { | ||
| 860 | promptManager.log(`Skipping prompt ${source} because it is an absolute prompt`); | ||
| 861 | return; | ||
| 862 | } | ||
| 863 | |||
| 858 | const index = target ? prompts.index(target) : prompts.index(source); | 864 | const index = target ? prompts.index(target) : prompts.index(source); |
| 859 | const collection = new MessageCollection(source); | 865 | const collection = new MessageCollection(source); |
| 860 | collection.add(Message.fromPrompt(prompt)); | 866 | collection.add(Message.fromPrompt(prompt)); |
| @@ -899,8 +905,8 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 899 | acc.push(prompt.identifier); | 905 | acc.push(prompt.identifier); |
| 900 | return acc; | 906 | return acc; |
| 901 | }, []); | 907 | }, []); |
| 902 | const userAbsolutePrompts = prompts.collection | 908 | const absolutePrompts = prompts.collection |
| 903 | .filter((prompt) => false === prompt.system_prompt && prompt.injection_position === INJECTION_POSITION.ABSOLUTE) | 909 | .filter((prompt) => prompt.injection_position === INJECTION_POSITION.ABSOLUTE) |
| 904 | .reduce((acc, prompt) => { | 910 | .reduce((acc, prompt) => { |
| 905 | acc.push(prompt); | 911 | acc.push(prompt); |
| 906 | return acc; | 912 | return acc; |
| @@ -965,7 +971,7 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 965 | } | 971 | } |
| 966 | 972 | ||
| 967 | // Add in-chat injections | 973 | // Add in-chat injections |
| 968 | messages = populationInjectionPrompts(userAbsolutePrompts, messages); | 974 | messages = populationInjectionPrompts(absolutePrompts, messages); |
| 969 | 975 | ||
| 970 | // Decide whether dialogue examples should always be added | 976 | // Decide whether dialogue examples should always be added |
| 971 | if (power_user.pin_examples) { | 977 | if (power_user.pin_examples) { |
| @@ -1102,6 +1108,18 @@ function preparePromptsForChatCompletion({ Scenario, charPersonality, name2, wor | |||
| 1102 | 1108 | ||
| 1103 | // Merge system prompts with prompt manager prompts | 1109 | // Merge system prompts with prompt manager prompts |
| 1104 | systemPrompts.forEach(prompt => { | 1110 | systemPrompts.forEach(prompt => { |
| 1111 | const collectionPrompt = prompts.get(prompt.identifier); | ||
| 1112 | |||
| 1113 | // Apply system prompt role/depth overrides if they set in the prompt manager | ||
| 1114 | if (collectionPrompt) { | ||
| 1115 | // In-Chat / Relative | ||
| 1116 | prompt.injection_position = collectionPrompt.injection_position ?? prompt.injection_position; | ||
| 1117 | // Depth for In-Chat | ||
| 1118 | prompt.injection_depth = collectionPrompt.injection_depth ?? prompt.injection_depth; | ||
| 1119 | // Role (system, user, assistant) | ||
| 1120 | prompt.role = collectionPrompt.role ?? prompt.role; | ||
| 1121 | } | ||
| 1122 | |||
| 1105 | const newPrompt = promptManager.preparePrompt(prompt); | 1123 | const newPrompt = promptManager.preparePrompt(prompt); |
| 1106 | const markerIndex = prompts.index(prompt.identifier); | 1124 | const markerIndex = prompts.index(prompt.identifier); |
| 1107 | 1125 | ||
| @@ -2370,7 +2388,7 @@ class Message { | |||
| 2370 | * @returns {Promise<string>} Compressed image as a Data URL. | 2388 | * @returns {Promise<string>} Compressed image as a Data URL. |
| 2371 | */ | 2389 | */ |
| 2372 | async compressImage(image) { | 2390 | async compressImage(image) { |
| 2373 | if ([chat_completion_sources.OPENROUTER, chat_completion_sources.MAKERSUITE].includes(oai_settings.chat_completion_source)) { | 2391 | if ([chat_completion_sources.OPENROUTER, chat_completion_sources.MAKERSUITE, chat_completion_sources.MISTRALAI].includes(oai_settings.chat_completion_source)) { |
| 2374 | const sizeThreshold = 2 * 1024 * 1024; | 2392 | const sizeThreshold = 2 * 1024 * 1024; |
| 2375 | const dataSize = image.length * 0.75; | 2393 | const dataSize = image.length * 0.75; |
| 2376 | const maxSide = 1024; | 2394 | const maxSide = 1024; |
| @@ -2747,7 +2765,7 @@ export class ChatCompletion { | |||
| 2747 | const message = { role: item.role, content: item.content, ...(item.name ? { name: item.name } : {}) }; | 2765 | const message = { role: item.role, content: item.content, ...(item.name ? { name: item.name } : {}) }; |
| 2748 | chat.push(message); | 2766 | chat.push(message); |
| 2749 | } else { | 2767 | } else { |
| 2750 | console.warn('Invalid message in collection', item); | 2768 | this.log(`Skipping invalid or empty message in collection: ${JSON.stringify(item)}`); |
| 2751 | } | 2769 | } |
| 2752 | } | 2770 | } |
| 2753 | return chat; | 2771 | return chat; |
| @@ -3216,12 +3234,12 @@ async function getStatusOpen() { | |||
| 3216 | 3234 | ||
| 3217 | const responseData = await response.json(); | 3235 | const responseData = await response.json(); |
| 3218 | 3236 | ||
| 3219 | if (!('error' in responseData)) { | ||
| 3220 | setOnlineStatus('Valid'); | ||
| 3221 | } | ||
| 3222 | if ('data' in responseData && Array.isArray(responseData.data)) { | 3237 | if ('data' in responseData && Array.isArray(responseData.data)) { |
| 3223 | saveModelList(responseData.data); | 3238 | saveModelList(responseData.data); |
| 3224 | } | 3239 | } |
| 3240 | if (!('error' in responseData)) { | ||
| 3241 | setOnlineStatus('Valid'); | ||
| 3242 | } | ||
| 3225 | } catch (error) { | 3243 | } catch (error) { |
| 3226 | console.error(error); | 3244 | console.error(error); |
| 3227 | 3245 | ||
| @@ -3986,6 +4004,8 @@ async function onModelChange() { | |||
| 3986 | $('#openai_max_context').attr('max', max_2mil); | 4004 | $('#openai_max_context').attr('max', max_2mil); |
| 3987 | } else if (value.includes('gemini-1.5-pro')) { | 4005 | } else if (value.includes('gemini-1.5-pro')) { |
| 3988 | $('#openai_max_context').attr('max', max_2mil); | 4006 | $('#openai_max_context').attr('max', max_2mil); |
| 4007 | } else if (value.match('gemini-1.5-flash-002')) { | ||
| 4008 | $('#openai_max_context').attr('max', max_2mil); | ||
| 3989 | } else if (value.includes('gemini-1.5-flash')) { | 4009 | } else if (value.includes('gemini-1.5-flash')) { |
| 3990 | $('#openai_max_context').attr('max', max_1mil); | 4010 | $('#openai_max_context').attr('max', max_1mil); |
| 3991 | } else if (value.includes('gemini-1.0-pro-vision') || value === 'gemini-pro-vision') { | 4011 | } else if (value.includes('gemini-1.0-pro-vision') || value === 'gemini-pro-vision') { |
| @@ -4097,6 +4117,8 @@ async function onModelChange() { | |||
| 4097 | $('#openai_max_context').attr('max', max_128k); | 4117 | $('#openai_max_context').attr('max', max_128k); |
| 4098 | } else if (oai_settings.mistralai_model.includes('mixtral-8x22b')) { | 4118 | } else if (oai_settings.mistralai_model.includes('mixtral-8x22b')) { |
| 4099 | $('#openai_max_context').attr('max', max_64k); | 4119 | $('#openai_max_context').attr('max', max_64k); |
| 4120 | } else if (oai_settings.mistralai_model.includes('pixtral')) { | ||
| 4121 | $('#openai_max_context').attr('max', max_128k); | ||
| 4100 | } else { | 4122 | } else { |
| 4101 | $('#openai_max_context').attr('max', max_32k); | 4123 | $('#openai_max_context').attr('max', max_32k); |
| 4102 | } | 4124 | } |
| @@ -4630,12 +4652,15 @@ export function isImageInliningSupported() { | |||
| 4630 | 'gemini-1.5-flash', | 4652 | 'gemini-1.5-flash', |
| 4631 | 'gemini-1.5-flash-latest', | 4653 | 'gemini-1.5-flash-latest', |
| 4632 | 'gemini-1.5-flash-001', | 4654 | 'gemini-1.5-flash-001', |
| 4655 | 'gemini-1.5-flash-002', | ||
| 4633 | 'gemini-1.5-flash-exp-0827', | 4656 | 'gemini-1.5-flash-exp-0827', |
| 4634 | 'gemini-1.5-flash-8b-exp-0827', | 4657 | 'gemini-1.5-flash-8b-exp-0827', |
| 4658 | 'gemini-1.5-flash-8b-exp-0924', | ||
| 4635 | 'gemini-1.0-pro-vision-latest', | 4659 | 'gemini-1.0-pro-vision-latest', |
| 4636 | 'gemini-1.5-pro', | 4660 | 'gemini-1.5-pro', |
| 4637 | 'gemini-1.5-pro-latest', | 4661 | 'gemini-1.5-pro-latest', |
| 4638 | 'gemini-1.5-pro-001', | 4662 | 'gemini-1.5-pro-001', |
| 4663 | 'gemini-1.5-pro-002', | ||
| 4639 | 'gemini-1.5-pro-exp-0801', | 4664 | 'gemini-1.5-pro-exp-0801', |
| 4640 | 'gemini-1.5-pro-exp-0827', | 4665 | 'gemini-1.5-pro-exp-0827', |
| 4641 | 'gemini-pro-vision', | 4666 | 'gemini-pro-vision', |
| @@ -4646,6 +4671,8 @@ export function isImageInliningSupported() { | |||
| 4646 | 'gpt-4o-mini', | 4671 | 'gpt-4o-mini', |
| 4647 | 'chatgpt-4o-latest', | 4672 | 'chatgpt-4o-latest', |
| 4648 | 'yi-vision', | 4673 | 'yi-vision', |
| 4674 | 'pixtral-latest', | ||
| 4675 | 'pixtral-12b-2409', | ||
| 4649 | ]; | 4676 | ]; |
| 4650 | 4677 | ||
| 4651 | switch (oai_settings.chat_completion_source) { | 4678 | switch (oai_settings.chat_completion_source) { |
| @@ -4661,6 +4688,8 @@ export function isImageInliningSupported() { | |||
| 4661 | return true; | 4688 | return true; |
| 4662 | case chat_completion_sources.ZEROONEAI: | 4689 | case chat_completion_sources.ZEROONEAI: |
| 4663 | return visionSupportedModels.some(model => oai_settings.zerooneai_model.includes(model)); | 4690 | return visionSupportedModels.some(model => oai_settings.zerooneai_model.includes(model)); |
| 4691 | case chat_completion_sources.MISTRALAI: | ||
| 4692 | return visionSupportedModels.some(model => oai_settings.mistralai_model.includes(model)); | ||
| 4664 | default: | 4693 | default: |
| 4665 | return false; | 4694 | return false; |
| 4666 | } | 4695 | } |
| @@ -4789,7 +4818,7 @@ function runProxyCallback(_, value) { | |||
| 4789 | return foundName; | 4818 | return foundName; |
| 4790 | } | 4819 | } |
| 4791 | 4820 | ||
| 4792 | export function initOpenai() { | 4821 | export function initOpenAI() { |
| 4793 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 4822 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 4794 | name: 'proxy', | 4823 | name: 'proxy', |
| 4795 | callback: runProxyCallback, | 4824 | callback: runProxyCallback, |
| @@ -4805,9 +4834,7 @@ export function initOpenai() { | |||
| 4805 | ], | 4834 | ], |
| 4806 | helpString: 'Sets a proxy preset by name.', | 4835 | helpString: 'Sets a proxy preset by name.', |
| 4807 | })); | 4836 | })); |
| 4808 | } | ||
| 4809 | 4837 | ||
| 4810 | $(document).ready(async function () { | ||
| 4811 | $('#test_api_button').on('click', testApiConnection); | 4838 | $('#test_api_button').on('click', testApiConnection); |
| 4812 | 4839 | ||
| 4813 | $('#scale-alt').on('change', function () { | 4840 | $('#scale-alt').on('change', function () { |
| @@ -5266,4 +5293,4 @@ $(document).ready(async function () { | |||
| 5266 | $('#openai_proxy_password_show').on('click', onProxyPasswordShowClick); | 5293 | $('#openai_proxy_password_show').on('click', onProxyPasswordShowClick); |
| 5267 | $('#customize_additional_parameters').on('click', onCustomizeParametersClick); | 5294 | $('#customize_additional_parameters').on('click', onCustomizeParametersClick); |
| 5268 | $('#openai_proxy_preset').on('change', onProxyPresetChange); | 5295 | $('#openai_proxy_preset').on('change', onProxyPresetChange); |
| 5269 | }); | 5296 | } |
| @@ -2,7 +2,7 @@ import { | |||
| 2 | characters, | 2 | characters, |
| 3 | chat, | 3 | chat, |
| 4 | chat_metadata, | 4 | chat_metadata, |
| 5 | default_avatar, | 5 | default_user_avatar, |
| 6 | eventSource, | 6 | eventSource, |
| 7 | event_types, | 7 | event_types, |
| 8 | getRequestHeaders, | 8 | getRequestHeaders, |
| @@ -357,7 +357,7 @@ async function createDummyPersona() { | |||
| 357 | // Date + name (only ASCII) to make it unique | 357 | // Date + name (only ASCII) to make it unique |
| 358 | const avatarId = `${Date.now()}-${personaName.replace(/[^a-zA-Z0-9]/g, '')}.png`; | 358 | const avatarId = `${Date.now()}-${personaName.replace(/[^a-zA-Z0-9]/g, '')}.png`; |
| 359 | initPersona(avatarId, personaName, ''); | 359 | initPersona(avatarId, personaName, ''); |
| 360 | await uploadUserAvatar(default_avatar, avatarId); | 360 | await uploadUserAvatar(default_user_avatar, avatarId); |
| 361 | } | 361 | } |
| 362 | 362 | ||
| 363 | /** | 363 | /** |
| @@ -944,7 +944,7 @@ async function onPersonasRestoreInput(e) { | |||
| 944 | // If the avatar is missing, upload it | 944 | // If the avatar is missing, upload it |
| 945 | if (!avatarsList.includes(key)) { | 945 | if (!avatarsList.includes(key)) { |
| 946 | warnings.push(`Persona image "${key}" (${value}) is missing, uploading default avatar`); | 946 | warnings.push(`Persona image "${key}" (${value}) is missing, uploading default avatar`); |
| 947 | await uploadUserAvatar(default_avatar, key); | 947 | await uploadUserAvatar(default_user_avatar, key); |
| 948 | } | 948 | } |
| 949 | } | 949 | } |
| 950 | 950 | ||
| @@ -32,6 +32,7 @@ import { | |||
| 32 | import { | 32 | import { |
| 33 | instruct_presets, | 33 | instruct_presets, |
| 34 | loadInstructMode, | 34 | loadInstructMode, |
| 35 | names_behavior_types, | ||
| 35 | selectInstructPreset, | 36 | selectInstructPreset, |
| 36 | } from './instruct-mode.js'; | 37 | } from './instruct-mode.js'; |
| 37 | 38 | ||
| @@ -49,6 +50,7 @@ import { AUTOCOMPLETE_SELECT_KEY, AUTOCOMPLETE_WIDTH } from './autocomplete/Auto | |||
| 49 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; | 50 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; |
| 50 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; | 51 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 51 | import { POPUP_TYPE, callGenericPopup } from './popup.js'; | 52 | import { POPUP_TYPE, callGenericPopup } from './popup.js'; |
| 53 | import { loadSystemPrompts } from './sysprompt.js'; | ||
| 52 | 54 | ||
| 53 | export { | 55 | export { |
| 54 | loadPowerUserSettings, | 56 | loadPowerUserSettings, |
| @@ -113,7 +115,6 @@ let power_user = { | |||
| 113 | pin_examples: false, | 115 | pin_examples: false, |
| 114 | strip_examples: false, | 116 | strip_examples: false, |
| 115 | trim_sentences: false, | 117 | trim_sentences: false, |
| 116 | include_newline: false, | ||
| 117 | always_force_name2: false, | 118 | always_force_name2: false, |
| 118 | user_prompt_bias: '', | 119 | user_prompt_bias: '', |
| 119 | show_user_prompt_bias: true, | 120 | show_user_prompt_bias: true, |
| @@ -205,11 +206,9 @@ let power_user = { | |||
| 205 | disable_group_trimming: false, | 206 | disable_group_trimming: false, |
| 206 | single_line: false, | 207 | single_line: false, |
| 207 | 208 | ||
| 208 | default_instruct: '', | ||
| 209 | instruct: { | 209 | instruct: { |
| 210 | enabled: false, | 210 | enabled: false, |
| 211 | preset: 'Alpaca', | 211 | preset: 'Alpaca', |
| 212 | system_prompt: 'Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\nWrite {{char}}\'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n', | ||
| 213 | input_sequence: '### Instruction:', | 212 | input_sequence: '### Instruction:', |
| 214 | input_suffix: '', | 213 | input_suffix: '', |
| 215 | output_sequence: '### Response:', | 214 | output_sequence: '### Response:', |
| @@ -224,8 +223,7 @@ let power_user = { | |||
| 224 | stop_sequence: '', | 223 | stop_sequence: '', |
| 225 | wrap: true, | 224 | wrap: true, |
| 226 | macro: true, | 225 | macro: true, |
| 227 | names: false, | 226 | names_behavior: names_behavior_types.FORCE, |
| 228 | names_force_groups: true, | ||
| 229 | activation_regex: '', | 227 | activation_regex: '', |
| 230 | bind_to_context: false, | 228 | bind_to_context: false, |
| 231 | user_alignment_message: '', | 229 | user_alignment_message: '', |
| @@ -234,7 +232,6 @@ let power_user = { | |||
| 234 | separator_sequence: '', | 232 | separator_sequence: '', |
| 235 | }, | 233 | }, |
| 236 | 234 | ||
| 237 | default_context: 'Default', | ||
| 238 | context: { | 235 | context: { |
| 239 | preset: 'Default', | 236 | preset: 'Default', |
| 240 | story_string: defaultStoryString, | 237 | story_string: defaultStoryString, |
| @@ -245,6 +242,12 @@ let power_user = { | |||
| 245 | names_as_stop_strings: true, | 242 | names_as_stop_strings: true, |
| 246 | }, | 243 | }, |
| 247 | 244 | ||
| 245 | sysprompt: { | ||
| 246 | enabled: true, | ||
| 247 | name: 'Neutral - Chat', | ||
| 248 | content: 'Write {{char}}\'s next reply in a fictional chat between {{char}} and {{user}}.', | ||
| 249 | }, | ||
| 250 | |||
| 248 | personas: {}, | 251 | personas: {}, |
| 249 | default_persona: null, | 252 | default_persona: null, |
| 250 | persona_descriptions: {}, | 253 | persona_descriptions: {}, |
| @@ -317,7 +320,6 @@ const contextControls = [ | |||
| 317 | // Existing power user settings | 320 | // Existing power user settings |
| 318 | { id: 'always-force-name2-checkbox', property: 'always_force_name2', isCheckbox: true, isGlobalSetting: true, defaultValue: true }, | 321 | { id: 'always-force-name2-checkbox', property: 'always_force_name2', isCheckbox: true, isGlobalSetting: true, defaultValue: true }, |
| 319 | { id: 'trim_sentences_checkbox', property: 'trim_sentences', isCheckbox: true, isGlobalSetting: true, defaultValue: false }, | 322 | { id: 'trim_sentences_checkbox', property: 'trim_sentences', isCheckbox: true, isGlobalSetting: true, defaultValue: false }, |
| 320 | { id: 'include_newline_checkbox', property: 'include_newline', isCheckbox: true, isGlobalSetting: true, defaultValue: false }, | ||
| 321 | { id: 'single_line', property: 'single_line', isCheckbox: true, isGlobalSetting: true, defaultValue: false }, | 323 | { id: 'single_line', property: 'single_line', isCheckbox: true, isGlobalSetting: true, defaultValue: false }, |
| 322 | ]; | 324 | ]; |
| 323 | 325 | ||
| @@ -1487,7 +1489,6 @@ async function loadPowerUserSettings(settings, data) { | |||
| 1487 | $('#collapse-newlines-checkbox').prop('checked', power_user.collapse_newlines); | 1489 | $('#collapse-newlines-checkbox').prop('checked', power_user.collapse_newlines); |
| 1488 | $('#always-force-name2-checkbox').prop('checked', power_user.always_force_name2); | 1490 | $('#always-force-name2-checkbox').prop('checked', power_user.always_force_name2); |
| 1489 | $('#trim_sentences_checkbox').prop('checked', power_user.trim_sentences); | 1491 | $('#trim_sentences_checkbox').prop('checked', power_user.trim_sentences); |
| 1490 | $('#include_newline_checkbox').prop('checked', power_user.include_newline); | ||
| 1491 | $('#render_formulas').prop('checked', power_user.render_formulas); | 1492 | $('#render_formulas').prop('checked', power_user.render_formulas); |
| 1492 | $('#disable_group_trimming').prop('checked', power_user.disable_group_trimming); | 1493 | $('#disable_group_trimming').prop('checked', power_user.disable_group_trimming); |
| 1493 | $('#markdown_escape_strings').val(power_user.markdown_escape_strings); | 1494 | $('#markdown_escape_strings').val(power_user.markdown_escape_strings); |
| @@ -1598,6 +1599,7 @@ async function loadPowerUserSettings(settings, data) { | |||
| 1598 | reloadMarkdownProcessor(power_user.render_formulas); | 1599 | reloadMarkdownProcessor(power_user.render_formulas); |
| 1599 | await loadInstructMode(data); | 1600 | await loadInstructMode(data); |
| 1600 | await loadContextSettings(); | 1601 | await loadContextSettings(); |
| 1602 | await loadSystemPrompts(data); | ||
| 1601 | loadMaxContextUnlocked(); | 1603 | loadMaxContextUnlocked(); |
| 1602 | switchWaifuMode(); | 1604 | switchWaifuMode(); |
| 1603 | switchSpoilerMode(); | 1605 | switchSpoilerMode(); |
| @@ -1817,29 +1819,8 @@ async function loadContextSettings() { | |||
| 1817 | } | 1819 | } |
| 1818 | } | 1820 | } |
| 1819 | 1821 | ||
| 1820 | highlightDefaultContext(); | ||
| 1821 | saveSettingsDebounced(); | 1822 | saveSettingsDebounced(); |
| 1822 | }); | 1823 | }); |
| 1823 | |||
| 1824 | $('#context_set_default').on('click', function () { | ||
| 1825 | if (power_user.context.preset !== power_user.default_context) { | ||
| 1826 | power_user.default_context = power_user.context.preset; | ||
| 1827 | $(this).addClass('default'); | ||
| 1828 | toastr.info(`Default context template set to ${power_user.default_context}`); | ||
| 1829 | |||
| 1830 | highlightDefaultContext(); | ||
| 1831 | |||
| 1832 | saveSettingsDebounced(); | ||
| 1833 | } | ||
| 1834 | }); | ||
| 1835 | |||
| 1836 | highlightDefaultContext(); | ||
| 1837 | } | ||
| 1838 | |||
| 1839 | function highlightDefaultContext() { | ||
| 1840 | $('#context_set_default').toggleClass('default', power_user.default_context === power_user.context.preset); | ||
| 1841 | $('#context_set_default').toggleClass('disabled', power_user.default_context === power_user.context.preset); | ||
| 1842 | $('#context_delete_preset').toggleClass('disabled', power_user.default_context === power_user.context.preset); | ||
| 1843 | } | 1824 | } |
| 1844 | 1825 | ||
| 1845 | /** | 1826 | /** |
| @@ -3069,19 +3050,6 @@ $(document).ready(() => { | |||
| 3069 | // if trim sentences is unchecked, include newline must be unchecked | 3050 | // if trim sentences is unchecked, include newline must be unchecked |
| 3070 | $('#trim_sentences_checkbox').change(function () { | 3051 | $('#trim_sentences_checkbox').change(function () { |
| 3071 | power_user.trim_sentences = !!$(this).prop('checked'); | 3052 | power_user.trim_sentences = !!$(this).prop('checked'); |
| 3072 | if (!$(this).prop('checked')) { | ||
| 3073 | $('#include_newline_checkbox').prop('checked', false); | ||
| 3074 | power_user.include_newline = false; | ||
| 3075 | } | ||
| 3076 | saveSettingsDebounced(); | ||
| 3077 | }); | ||
| 3078 | |||
| 3079 | $('#include_newline_checkbox').change(function () { | ||
| 3080 | power_user.include_newline = !!$(this).prop('checked'); | ||
| 3081 | if ($(this).prop('checked')) { | ||
| 3082 | $('#trim_sentences_checkbox').prop('checked', true); | ||
| 3083 | power_user.trim_sentences = true; | ||
| 3084 | } | ||
| 3085 | saveSettingsDebounced(); | 3053 | saveSettingsDebounced(); |
| 3086 | }); | 3054 | }); |
| 3087 | 3055 | ||
| @@ -18,13 +18,16 @@ import { | |||
| 18 | import { groups, selected_group } from './group-chats.js'; | 18 | import { groups, selected_group } from './group-chats.js'; |
| 19 | import { instruct_presets } from './instruct-mode.js'; | 19 | import { instruct_presets } from './instruct-mode.js'; |
| 20 | import { kai_settings } from './kai-settings.js'; | 20 | import { kai_settings } from './kai-settings.js'; |
| 21 | import { Popup } from './popup.js'; | 21 | import { convertNovelPreset } from './nai-settings.js'; |
| 22 | import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js'; | ||
| 22 | import { context_presets, getContextSettings, power_user } from './power-user.js'; | 23 | import { context_presets, getContextSettings, power_user } from './power-user.js'; |
| 23 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | 24 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| 24 | import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js'; | 25 | import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js'; |
| 25 | import { enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; | 26 | import { enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 26 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; | 27 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; |
| 27 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | 28 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 29 | import { checkForSystemPromptInInstructTemplate, system_prompts } from './sysprompt.js'; | ||
| 30 | import { renderTemplateAsync } from './templates.js'; | ||
| 28 | import { | 31 | import { |
| 29 | textgenerationwebui_preset_names, | 32 | textgenerationwebui_preset_names, |
| 30 | textgenerationwebui_presets, | 33 | textgenerationwebui_presets, |
| @@ -71,7 +74,7 @@ function autoSelectPreset() { | |||
| 71 | * @param {string} apiId API id | 74 | * @param {string} apiId API id |
| 72 | * @returns {PresetManager} Preset manager | 75 | * @returns {PresetManager} Preset manager |
| 73 | */ | 76 | */ |
| 74 | function getPresetManager(apiId = '') { | 77 | export function getPresetManager(apiId = '') { |
| 75 | if (!apiId) { | 78 | if (!apiId) { |
| 76 | apiId = main_api == 'koboldhorde' ? 'kobold' : main_api; | 79 | apiId = main_api == 'koboldhorde' ? 'kobold' : main_api; |
| 77 | } | 80 | } |
| @@ -102,6 +105,215 @@ class PresetManager { | |||
| 102 | this.apiId = apiId; | 105 | this.apiId = apiId; |
| 103 | } | 106 | } |
| 104 | 107 | ||
| 108 | static masterSections = { | ||
| 109 | 'instruct': { | ||
| 110 | name: 'Instruct Template', | ||
| 111 | getData: () => { | ||
| 112 | const manager = getPresetManager('instruct'); | ||
| 113 | const name = manager.getSelectedPresetName(); | ||
| 114 | return manager.getPresetSettings(name); | ||
| 115 | }, | ||
| 116 | setData: (data) => { | ||
| 117 | const manager = getPresetManager('instruct'); | ||
| 118 | const name = data.name; | ||
| 119 | return manager.savePreset(name, data); | ||
| 120 | }, | ||
| 121 | isValid: (data) => PresetManager.isPossiblyInstructData(data), | ||
| 122 | }, | ||
| 123 | 'context': { | ||
| 124 | name: 'Context Template', | ||
| 125 | getData: () => { | ||
| 126 | const manager = getPresetManager('context'); | ||
| 127 | const name = manager.getSelectedPresetName(); | ||
| 128 | return manager.getPresetSettings(name); | ||
| 129 | }, | ||
| 130 | setData: (data) => { | ||
| 131 | const manager = getPresetManager('context'); | ||
| 132 | const name = data.name; | ||
| 133 | return manager.savePreset(name, data); | ||
| 134 | }, | ||
| 135 | isValid: (data) => PresetManager.isPossiblyContextData(data), | ||
| 136 | }, | ||
| 137 | 'sysprompt': { | ||
| 138 | name: 'System Prompt', | ||
| 139 | getData: () => { | ||
| 140 | const manager = getPresetManager('sysprompt'); | ||
| 141 | const name = manager.getSelectedPresetName(); | ||
| 142 | return manager.getPresetSettings(name); | ||
| 143 | }, | ||
| 144 | setData: (data) => { | ||
| 145 | const manager = getPresetManager('sysprompt'); | ||
| 146 | const name = data.name; | ||
| 147 | return manager.savePreset(name, data); | ||
| 148 | }, | ||
| 149 | isValid: (data) => PresetManager.isPossiblySystemPromptData(data), | ||
| 150 | }, | ||
| 151 | 'preset': { | ||
| 152 | name: 'Text Completion Preset', | ||
| 153 | getData: () => { | ||
| 154 | const manager = getPresetManager('textgenerationwebui'); | ||
| 155 | const name = manager.getSelectedPresetName(); | ||
| 156 | const data = manager.getPresetSettings(name); | ||
| 157 | data['name'] = name; | ||
| 158 | return data; | ||
| 159 | }, | ||
| 160 | setData: (data) => { | ||
| 161 | const manager = getPresetManager('textgenerationwebui'); | ||
| 162 | const name = data.name; | ||
| 163 | return manager.savePreset(name, data); | ||
| 164 | }, | ||
| 165 | isValid: (data) => PresetManager.isPossiblyTextCompletionData(data), | ||
| 166 | }, | ||
| 167 | }; | ||
| 168 | |||
| 169 | static isPossiblyInstructData(data) { | ||
| 170 | const instructProps = ['name', 'input_sequence', 'output_sequence']; | ||
| 171 | return data && instructProps.every(prop => Object.keys(data).includes(prop)); | ||
| 172 | } | ||
| 173 | |||
| 174 | static isPossiblyContextData(data) { | ||
| 175 | const contextProps = ['name', 'story_string']; | ||
| 176 | return data && contextProps.every(prop => Object.keys(data).includes(prop)); | ||
| 177 | } | ||
| 178 | |||
| 179 | static isPossiblySystemPromptData(data) { | ||
| 180 | const sysPromptProps = ['name', 'content']; | ||
| 181 | return data && sysPromptProps.every(prop => Object.keys(data).includes(prop)); | ||
| 182 | } | ||
| 183 | |||
| 184 | static isPossiblyTextCompletionData(data) { | ||
| 185 | const textCompletionProps = ['temp', 'top_k', 'top_p', 'rep_pen']; | ||
| 186 | return data && textCompletionProps.every(prop => Object.keys(data).includes(prop)); | ||
| 187 | } | ||
| 188 | |||
| 189 | /** | ||
| 190 | * Imports master settings from JSON data. | ||
| 191 | * @param {object} data Data to import | ||
| 192 | * @param {string} fileName File name | ||
| 193 | * @returns {Promise<void>} | ||
| 194 | */ | ||
| 195 | static async performMasterImport(data, fileName) { | ||
| 196 | if (!data || typeof data !== 'object') { | ||
| 197 | toastr.error('Invalid data provided for master import'); | ||
| 198 | return; | ||
| 199 | } | ||
| 200 | |||
| 201 | // Check for legacy file imports | ||
| 202 | // 1. Instruct Template | ||
| 203 | if (this.isPossiblyInstructData(data)) { | ||
| 204 | toastr.info('Importing instruct template...', 'Instruct template detected'); | ||
| 205 | return await getPresetManager('instruct').savePreset(data.name, data); | ||
| 206 | } | ||
| 207 | |||
| 208 | // 2. Context Template | ||
| 209 | if (this.isPossiblyContextData(data)) { | ||
| 210 | toastr.info('Importing as context template...', 'Context template detected'); | ||
| 211 | return await getPresetManager('context').savePreset(data.name, data); | ||
| 212 | } | ||
| 213 | |||
| 214 | // 3. System Prompt | ||
| 215 | if (this.isPossiblySystemPromptData(data)) { | ||
| 216 | toastr.info('Importing as system prompt...', 'System prompt detected'); | ||
| 217 | return await getPresetManager('sysprompt').savePreset(data.name, data); | ||
| 218 | } | ||
| 219 | |||
| 220 | // 4. Text Completion settings | ||
| 221 | if (this.isPossiblyTextCompletionData(data)) { | ||
| 222 | toastr.info('Importing as settings preset...', 'Text Completion settings detected'); | ||
| 223 | return await getPresetManager('textgenerationwebui').savePreset(fileName, data); | ||
| 224 | } | ||
| 225 | |||
| 226 | const validSections = []; | ||
| 227 | for (const [key, section] of Object.entries(this.masterSections)) { | ||
| 228 | if (key in data && section.isValid(data[key])) { | ||
| 229 | validSections.push(key); | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | if (validSections.length === 0) { | ||
| 234 | toastr.error('No valid sections found in imported data'); | ||
| 235 | return; | ||
| 236 | } | ||
| 237 | |||
| 238 | const sectionNames = validSections.reduce((acc, key) => { | ||
| 239 | acc[key] = { key: key, name: this.masterSections[key].name, preset: data[key]?.name || '' }; | ||
| 240 | return acc; | ||
| 241 | }, {}); | ||
| 242 | |||
| 243 | const html = $(await renderTemplateAsync('masterImport', { sections: sectionNames })); | ||
| 244 | const popup = new Popup(html, POPUP_TYPE.CONFIRM, '', { | ||
| 245 | okButton: 'Import', | ||
| 246 | cancelButton: 'Cancel', | ||
| 247 | }); | ||
| 248 | |||
| 249 | const result = await popup.show(); | ||
| 250 | |||
| 251 | // Import cancelled | ||
| 252 | if (result !== POPUP_RESULT.AFFIRMATIVE) { | ||
| 253 | return; | ||
| 254 | } | ||
| 255 | |||
| 256 | const importedSections = []; | ||
| 257 | const confirmedSections = html.find('input:checked').map((_, el) => el instanceof HTMLInputElement && el.value).get(); | ||
| 258 | |||
| 259 | if (confirmedSections.length === 0) { | ||
| 260 | toastr.info('No sections selected for import'); | ||
| 261 | return; | ||
| 262 | } | ||
| 263 | |||
| 264 | for (const section of confirmedSections) { | ||
| 265 | const sectionData = data[section]; | ||
| 266 | const masterSection = this.masterSections[section]; | ||
| 267 | if (sectionData && masterSection) { | ||
| 268 | await masterSection.setData(sectionData); | ||
| 269 | importedSections.push(masterSection.name); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | toastr.success(`Imported ${importedSections.length} settings: ${importedSections.join(', ')}`); | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * Exports master settings to JSON data. | ||
| 278 | * @returns {Promise<string>} JSON data | ||
| 279 | */ | ||
| 280 | static async performMasterExport() { | ||
| 281 | const sectionNames = Object.entries(this.masterSections).reduce((acc, [key, section]) => { | ||
| 282 | acc[key] = { key: key, name: section.name, checked: key !== 'preset' }; | ||
| 283 | return acc; | ||
| 284 | }, {}); | ||
| 285 | const html = $(await renderTemplateAsync('masterExport', { sections: sectionNames })); | ||
| 286 | |||
| 287 | const popup = new Popup(html, POPUP_TYPE.CONFIRM, '', { | ||
| 288 | okButton: 'Export', | ||
| 289 | cancelButton: 'Cancel', | ||
| 290 | }); | ||
| 291 | |||
| 292 | const result = await popup.show(); | ||
| 293 | |||
| 294 | // Export cancelled | ||
| 295 | if (result !== POPUP_RESULT.AFFIRMATIVE) { | ||
| 296 | return; | ||
| 297 | } | ||
| 298 | |||
| 299 | const confirmedSections = html.find('input:checked').map((_, el) => el instanceof HTMLInputElement && el.value).get(); | ||
| 300 | const data = {}; | ||
| 301 | |||
| 302 | if (confirmedSections.length === 0) { | ||
| 303 | toastr.info('No sections selected for export'); | ||
| 304 | return; | ||
| 305 | } | ||
| 306 | |||
| 307 | for (const section of confirmedSections) { | ||
| 308 | const masterSection = this.masterSections[section]; | ||
| 309 | if (masterSection) { | ||
| 310 | data[section] = masterSection.getData(); | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | return JSON.stringify(data, null, 4); | ||
| 315 | } | ||
| 316 | |||
| 105 | /** | 317 | /** |
| 106 | * Gets all preset names. | 318 | * Gets all preset names. |
| 107 | * @returns {string[]} List of preset names | 319 | * @returns {string[]} List of preset names |
| @@ -182,6 +394,14 @@ class PresetManager { | |||
| 182 | } | 394 | } |
| 183 | 395 | ||
| 184 | async savePreset(name, settings) { | 396 | async savePreset(name, settings) { |
| 397 | if (this.apiId === 'instruct' && settings) { | ||
| 398 | await checkForSystemPromptInInstructTemplate(name, settings); | ||
| 399 | } | ||
| 400 | |||
| 401 | if (this.apiId === 'novel' && settings) { | ||
| 402 | settings = convertNovelPreset(settings); | ||
| 403 | } | ||
| 404 | |||
| 185 | const preset = settings ?? this.getPresetSettings(name); | 405 | const preset = settings ?? this.getPresetSettings(name); |
| 186 | 406 | ||
| 187 | const response = await fetch('/api/presets/save', { | 407 | const response = await fetch('/api/presets/save', { |
| @@ -228,6 +448,10 @@ class PresetManager { | |||
| 228 | presets = instruct_presets; | 448 | presets = instruct_presets; |
| 229 | preset_names = instruct_presets.map(x => x.name); | 449 | preset_names = instruct_presets.map(x => x.name); |
| 230 | break; | 450 | break; |
| 451 | case 'sysprompt': | ||
| 452 | presets = system_prompts; | ||
| 453 | preset_names = system_prompts.map(x => x.name); | ||
| 454 | break; | ||
| 231 | default: | 455 | default: |
| 232 | console.warn(`Unknown API ID ${this.apiId}`); | 456 | console.warn(`Unknown API ID ${this.apiId}`); |
| 233 | } | 457 | } |
| @@ -236,11 +460,11 @@ class PresetManager { | |||
| 236 | } | 460 | } |
| 237 | 461 | ||
| 238 | isKeyedApi() { | 462 | isKeyedApi() { |
| 239 | return this.apiId == 'textgenerationwebui' || this.apiId == 'context' || this.apiId == 'instruct'; | 463 | return this.apiId == 'textgenerationwebui' || this.isAdvancedFormatting(); |
| 240 | } | 464 | } |
| 241 | 465 | ||
| 242 | isAdvancedFormatting() { | 466 | isAdvancedFormatting() { |
| 243 | return this.apiId == 'context' || this.apiId == 'instruct'; | 467 | return this.apiId == 'context' || this.apiId == 'instruct' || this.apiId == 'sysprompt'; |
| 244 | } | 468 | } |
| 245 | 469 | ||
| 246 | updateList(name, preset) { | 470 | updateList(name, preset) { |
| @@ -298,6 +522,11 @@ class PresetManager { | |||
| 298 | instruct_preset['name'] = name || power_user.instruct.preset; | 522 | instruct_preset['name'] = name || power_user.instruct.preset; |
| 299 | return instruct_preset; | 523 | return instruct_preset; |
| 300 | } | 524 | } |
| 525 | case 'sysprompt': { | ||
| 526 | const sysprompt_preset = structuredClone(power_user.sysprompt); | ||
| 527 | sysprompt_preset['name'] = name || power_user.sysprompt.preset; | ||
| 528 | return sysprompt_preset; | ||
| 529 | } | ||
| 301 | default: | 530 | default: |
| 302 | console.warn(`Unknown API ID ${apiId}`); | 531 | console.warn(`Unknown API ID ${apiId}`); |
| 303 | return {}; | 532 | return {}; |
| @@ -601,11 +830,6 @@ export async function initPresetManager() { | |||
| 601 | return; | 830 | return; |
| 602 | } | 831 | } |
| 603 | 832 | ||
| 604 | // default context preset cannot be deleted | ||
| 605 | if (apiId == 'context' && power_user.default_context === power_user.context.preset) { | ||
| 606 | return; | ||
| 607 | } | ||
| 608 | |||
| 609 | const headerText = !presetManager.isAdvancedFormatting() ? 'Delete this preset?' : 'Delete this template?'; | 833 | const headerText = !presetManager.isAdvancedFormatting() ? 'Delete this preset?' : 'Delete this template?'; |
| 610 | const confirm = await Popup.show.confirm(headerText, 'This action is irreversible and your current settings will be overwritten.'); | 834 | const confirm = await Popup.show.confirm(headerText, 'This action is irreversible and your current settings will be overwritten.'); |
| 611 | if (!confirm) { | 835 | if (!confirm) { |
| @@ -682,4 +906,35 @@ export async function initPresetManager() { | |||
| 682 | toastr.success(successToast); | 906 | toastr.success(successToast); |
| 683 | } | 907 | } |
| 684 | }); | 908 | }); |
| 909 | |||
| 910 | $('#af_master_import').on('click', () => { | ||
| 911 | $('#af_master_import_file').trigger('click'); | ||
| 912 | }); | ||
| 913 | |||
| 914 | $('#af_master_import_file').on('change', async function (e) { | ||
| 915 | if (!(e.target instanceof HTMLInputElement)) { | ||
| 916 | return; | ||
| 917 | } | ||
| 918 | const file = e.target.files[0]; | ||
| 919 | |||
| 920 | if (!file) { | ||
| 921 | return; | ||
| 922 | } | ||
| 923 | |||
| 924 | const data = await parseJsonFile(file); | ||
| 925 | const fileName = file.name.replace('.json', ''); | ||
| 926 | await PresetManager.performMasterImport(data, fileName); | ||
| 927 | e.target.value = null; | ||
| 928 | }); | ||
| 929 | |||
| 930 | $('#af_master_export').on('click', async () => { | ||
| 931 | const data = await PresetManager.performMasterExport(); | ||
| 932 | |||
| 933 | if (!data) { | ||
| 934 | return; | ||
| 935 | } | ||
| 936 | |||
| 937 | const shortDate = new Date().toISOString().split('T')[0]; | ||
| 938 | download(data, `ST-formatting-${shortDate}.json`, 'application/json'); | ||
| 939 | }); | ||
| 685 | } | 940 | } |
| @@ -0,0 +1,250 @@ | |||
| 1 | import { saveSettingsDebounced } from '../script.js'; | ||
| 2 | import { callGenericPopup, POPUP_TYPE } from './popup.js'; | ||
| 3 | import { power_user } from './power-user.js'; | ||
| 4 | import { getPresetManager } from './preset-manager.js'; | ||
| 5 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | ||
| 6 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; | ||
| 7 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; | ||
| 8 | import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; | ||
| 9 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | ||
| 10 | import { renderTemplateAsync } from './templates.js'; | ||
| 11 | import { isTrueBoolean, resetScrollHeight } from './utils.js'; | ||
| 12 | |||
| 13 | export let system_prompts = []; | ||
| 14 | |||
| 15 | const $enabled = $('#sysprompt_enabled'); | ||
| 16 | const $select = $('#sysprompt_select'); | ||
| 17 | const $content = $('#sysprompt_content'); | ||
| 18 | const $contentBlock = $('#SystemPromptBlock'); | ||
| 19 | |||
| 20 | async function migrateSystemPromptFromInstructMode() { | ||
| 21 | if ('system_prompt' in power_user.instruct) { | ||
| 22 | const prompt = String(power_user.instruct.system_prompt); | ||
| 23 | delete power_user.instruct.system_prompt; | ||
| 24 | power_user.sysprompt.enabled = power_user.instruct.enabled; | ||
| 25 | power_user.sysprompt.content = prompt; | ||
| 26 | |||
| 27 | const existingPromptName = system_prompts.find(x => x.content === prompt)?.name; | ||
| 28 | |||
| 29 | if (existingPromptName) { | ||
| 30 | power_user.sysprompt.name = existingPromptName; | ||
| 31 | } else { | ||
| 32 | const data = { name: `[Migrated] ${power_user.instruct.preset}`, content: prompt }; | ||
| 33 | await getPresetManager('sysprompt')?.savePreset(data.name, data); | ||
| 34 | power_user.sysprompt.name = data.name; | ||
| 35 | } | ||
| 36 | |||
| 37 | saveSettingsDebounced(); | ||
| 38 | toastr.info('System prompt settings have been moved from the Instruct Mode.', 'Migration notice', { timeOut: 5000 }); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Loads sysprompt settings from the given data object. | ||
| 44 | * @param {object} data Settings data object. | ||
| 45 | */ | ||
| 46 | export async function loadSystemPrompts(data) { | ||
| 47 | if (data.sysprompt !== undefined) { | ||
| 48 | system_prompts = data.sysprompt; | ||
| 49 | } | ||
| 50 | |||
| 51 | await migrateSystemPromptFromInstructMode(); | ||
| 52 | toggleSystemPromptDisabledControls(); | ||
| 53 | |||
| 54 | for (const prompt of system_prompts) { | ||
| 55 | $('<option>').val(prompt.name).text(prompt.name).appendTo($select); | ||
| 56 | } | ||
| 57 | |||
| 58 | $enabled.prop('checked', power_user.sysprompt.enabled); | ||
| 59 | $select.val(power_user.sysprompt.name); | ||
| 60 | $content.val(power_user.sysprompt.content); | ||
| 61 | if (!CSS.supports('field-sizing', 'content')) { | ||
| 62 | await resetScrollHeight($content); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Checks if the instruct template has a system prompt and prompts the user to save it as a system prompt. | ||
| 68 | * @param {string} name Name of the instruct template | ||
| 69 | * @param {object} template Instruct template object | ||
| 70 | */ | ||
| 71 | export async function checkForSystemPromptInInstructTemplate(name, template) { | ||
| 72 | if (!template || !name || typeof name !== 'string' || typeof template !== 'object') { | ||
| 73 | return; | ||
| 74 | } | ||
| 75 | if ('system_prompt' in template && template.system_prompt) { | ||
| 76 | const existingName = system_prompts.find(x => x.content === template.system_prompt)?.name; | ||
| 77 | const html = await renderTemplateAsync('migrateInstructPrompt', { prompt: template.system_prompt, existing: existingName }); | ||
| 78 | const confirm = await callGenericPopup(html, POPUP_TYPE.CONFIRM); | ||
| 79 | if (confirm) { | ||
| 80 | const migratedName = `[Migrated] ${name}`; | ||
| 81 | const prompt = { name: migratedName, content: template.system_prompt }; | ||
| 82 | const presetManager = getPresetManager('sysprompt'); | ||
| 83 | await presetManager.savePreset(migratedName, prompt); | ||
| 84 | toastr.success(`System prompt "${migratedName}" has been saved.`); | ||
| 85 | } else { | ||
| 86 | toastr.info('System prompt has been discarded.'); | ||
| 87 | } | ||
| 88 | |||
| 89 | delete template.system_prompt; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | function toggleSystemPromptDisabledControls() { | ||
| 94 | $enabled.parent().find('i').toggleClass('toggleEnabled', !!power_user.sysprompt.enabled); | ||
| 95 | $contentBlock.toggleClass('disabled', !power_user.sysprompt.enabled); | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * Sets the system prompt state. | ||
| 100 | * @param {boolean} state System prompt state | ||
| 101 | * @returns {string} Empty string | ||
| 102 | */ | ||
| 103 | function setSystemPromptStateCallback(state) { | ||
| 104 | power_user.sysprompt.enabled = state; | ||
| 105 | $enabled.prop('checked', state); | ||
| 106 | toggleSystemPromptDisabledControls(); | ||
| 107 | saveSettingsDebounced(); | ||
| 108 | return ''; | ||
| 109 | } | ||
| 110 | |||
| 111 | function toggleSystemPromptCallback(_args, state) { | ||
| 112 | if (!state || typeof state !== 'string') { | ||
| 113 | return String(power_user.sysprompt.enabled); | ||
| 114 | } | ||
| 115 | |||
| 116 | const newState = isTrueBoolean(state); | ||
| 117 | setSystemPromptStateCallback(newState); | ||
| 118 | return String(power_user.sysprompt.enabled); | ||
| 119 | } | ||
| 120 | |||
| 121 | function selectSystemPromptCallback(args, name) { | ||
| 122 | if (!power_user.sysprompt.enabled && !isTrueBoolean(args.forceGet)) { | ||
| 123 | return ''; | ||
| 124 | } | ||
| 125 | |||
| 126 | if (!name) { | ||
| 127 | return power_user.sysprompt.name ?? ''; | ||
| 128 | } | ||
| 129 | |||
| 130 | const quiet = isTrueBoolean(args?.quiet); | ||
| 131 | const systemPromptNames = system_prompts.map(preset => preset.name); | ||
| 132 | let foundName = systemPromptNames.find(x => x.toLowerCase() === name.toLowerCase()); | ||
| 133 | |||
| 134 | if (!foundName) { | ||
| 135 | const fuse = new Fuse(systemPromptNames); | ||
| 136 | const result = fuse.search(name); | ||
| 137 | |||
| 138 | if (result.length === 0) { | ||
| 139 | !quiet && toastr.warning(`System prompt "${name}" not found`); | ||
| 140 | return ''; | ||
| 141 | } | ||
| 142 | |||
| 143 | foundName = result[0].item; | ||
| 144 | } | ||
| 145 | |||
| 146 | $select.val(foundName).trigger('input'); | ||
| 147 | !quiet && toastr.success(`System prompt "${foundName}" selected`); | ||
| 148 | return foundName; | ||
| 149 | } | ||
| 150 | |||
| 151 | export function initSystemPrompts() { | ||
| 152 | $enabled.on('input', function () { | ||
| 153 | power_user.sysprompt.enabled = !!$(this).prop('checked'); | ||
| 154 | toggleSystemPromptDisabledControls(); | ||
| 155 | saveSettingsDebounced(); | ||
| 156 | }); | ||
| 157 | |||
| 158 | $select.on('change', async function () { | ||
| 159 | if (!power_user.sysprompt.enabled) { | ||
| 160 | $enabled.prop('checked', true).trigger('input'); | ||
| 161 | } | ||
| 162 | |||
| 163 | const name = String($(this).val()); | ||
| 164 | const prompt = system_prompts.find(p => p.name === name); | ||
| 165 | if (prompt) { | ||
| 166 | $content.val(prompt.content); | ||
| 167 | if (!CSS.supports('field-sizing', 'content')) { | ||
| 168 | await resetScrollHeight($content); | ||
| 169 | } | ||
| 170 | |||
| 171 | power_user.sysprompt.name = name; | ||
| 172 | power_user.sysprompt.content = prompt.content; | ||
| 173 | } | ||
| 174 | saveSettingsDebounced(); | ||
| 175 | }); | ||
| 176 | |||
| 177 | $content.on('input', function () { | ||
| 178 | power_user.sysprompt.content = String($(this).val()); | ||
| 179 | saveSettingsDebounced(); | ||
| 180 | }); | ||
| 181 | |||
| 182 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | ||
| 183 | name: 'sysprompt', | ||
| 184 | aliases: ['system-prompt'], | ||
| 185 | callback: selectSystemPromptCallback, | ||
| 186 | returns: 'current prompt name', | ||
| 187 | namedArgumentList: [ | ||
| 188 | SlashCommandNamedArgument.fromProps({ | ||
| 189 | name: 'quiet', | ||
| 190 | description: 'Suppress the toast message on prompt change', | ||
| 191 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 192 | defaultValue: 'false', | ||
| 193 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 194 | }), | ||
| 195 | SlashCommandNamedArgument.fromProps({ | ||
| 196 | name: 'forceGet', | ||
| 197 | description: 'Force getting a name even if system prompt is disabled', | ||
| 198 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 199 | defaultValue: 'false', | ||
| 200 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 201 | }), | ||
| 202 | ], | ||
| 203 | unnamedArgumentList: [ | ||
| 204 | SlashCommandArgument.fromProps({ | ||
| 205 | description: 'system prompt name', | ||
| 206 | typeList: [ARGUMENT_TYPE.STRING], | ||
| 207 | enumProvider: () => system_prompts.map(x => new SlashCommandEnumValue(x.name, null, enumTypes.enum, enumIcons.preset)), | ||
| 208 | }), | ||
| 209 | ], | ||
| 210 | helpString: ` | ||
| 211 | <div> | ||
| 212 | Selects a system prompt by name, using fuzzy search to find the closest match. | ||
| 213 | Gets the current system prompt if no name is provided and sysprompt is enabled or <code>forceGet=true</code> is passed. | ||
| 214 | </div> | ||
| 215 | <div> | ||
| 216 | <strong>Example:</strong> | ||
| 217 | <ul> | ||
| 218 | <li> | ||
| 219 | <pre><code class="language-stscript">/sysprompt </code></pre> | ||
| 220 | </li> | ||
| 221 | </ul> | ||
| 222 | </div> | ||
| 223 | `, | ||
| 224 | })); | ||
| 225 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | ||
| 226 | name: 'sysprompt-on', | ||
| 227 | aliases: ['sysprompt-enable'], | ||
| 228 | callback: () => setSystemPromptStateCallback(true), | ||
| 229 | helpString: 'Enables system prompt.', | ||
| 230 | })); | ||
| 231 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | ||
| 232 | name: 'sysprompt-off', | ||
| 233 | aliases: ['sysprompt-disable'], | ||
| 234 | callback: () => setSystemPromptStateCallback(false), | ||
| 235 | helpString: 'Disables system prompt', | ||
| 236 | })); | ||
| 237 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | ||
| 238 | name: 'sysprompt-state', | ||
| 239 | aliases: ['sysprompt-toggle'], | ||
| 240 | helpString: 'Gets the current system prompt state. If an argument is provided, it will set the system prompt state.', | ||
| 241 | unnamedArgumentList: [ | ||
| 242 | SlashCommandArgument.fromProps({ | ||
| 243 | description: 'system prompt state', | ||
| 244 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 245 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 246 | }), | ||
| 247 | ], | ||
| 248 | callback: toggleSystemPromptCallback, | ||
| 249 | })); | ||
| 250 | } | ||
| @@ -57,8 +57,8 @@ | |||
| 57 | <li><tt>{{maxPrompt}}</tt> – <span data-i18n="help_macros_41">max allowed prompt length in tokens = (context size - response length)</span></li> | 57 | <li><tt>{{maxPrompt}}</tt> – <span data-i18n="help_macros_41">max allowed prompt length in tokens = (context size - response length)</span></li> |
| 58 | <li><tt>{{exampleSeparator}}</tt> – <span data-i18n="help_macros_42">context template example dialogues separator</span></li> | 58 | <li><tt>{{exampleSeparator}}</tt> – <span data-i18n="help_macros_42">context template example dialogues separator</span></li> |
| 59 | <li><tt>{{chatStart}}</tt> – <span data-i18n="help_macros_43">context template chat start line</span></li> | 59 | <li><tt>{{chatStart}}</tt> – <span data-i18n="help_macros_43">context template chat start line</span></li> |
| 60 | <li><tt>{{systemPrompt}}</tt> – <span data-i18n="help_macros_44">main system prompt (either character prompt override if chosen, or instructSystemPrompt)</span></li> | 60 | <li><tt>{{systemPrompt}}</tt> – <span data-i18n="help_macros_44">system prompt content if enabled (either character prompt override if allowed, or defaultSystemPrompt)</span></li> |
| 61 | <li><tt>{{instructSystemPrompt}}</tt> – <span data-i18n="help_macros_45">instruct system prompt</span></li> | 61 | <li><tt>{{defaultSystemPrompt}}</tt> – <span data-i18n="help_macros_45">system prompt content</span></li> |
| 62 | <li><tt>{{instructSystemPromptPrefix}}</tt> – <span data-i18n="help_macros_46">instruct system prompt prefix sequence</span></li> | 62 | <li><tt>{{instructSystemPromptPrefix}}</tt> – <span data-i18n="help_macros_46">instruct system prompt prefix sequence</span></li> |
| 63 | <li><tt>{{instructSystemPromptSuffix}}</tt> – <span data-i18n="help_macros_47">instruct system prompt suffix sequence</span></li> | 63 | <li><tt>{{instructSystemPromptSuffix}}</tt> – <span data-i18n="help_macros_47">instruct system prompt suffix sequence</span></li> |
| 64 | <li><tt>{{instructUserPrefix}}</tt> – <span data-i18n="help_macros_48">instruct user prefix sequence</span></li> | 64 | <li><tt>{{instructUserPrefix}}</tt> – <span data-i18n="help_macros_48">instruct user prefix sequence</span></li> |
| @@ -0,0 +1,17 @@ | |||
| 1 | <h3> | ||
| 2 | Choose what to export | ||
| 3 | </h3> | ||
| 4 | <div class="flex-container flexFlowColumn justifyLeft"> | ||
| 5 | {{#each sections}} | ||
| 6 | {{#with this}} | ||
| 7 | <label class="checkbox_label"> | ||
| 8 | {{#if checked}} | ||
| 9 | <input type="checkbox" value="{{key}}" checked /> | ||
| 10 | {{else}} | ||
| 11 | <input type="checkbox" value="{{key}}" /> | ||
| 12 | {{/if}} | ||
| 13 | <span data-i18n="{{name}}">{{name}}</span> | ||
| 14 | </label> | ||
| 15 | {{/with}} | ||
| 16 | {{/each}} | ||
| 17 | </div> | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | <h3> | ||
| 2 | Choose what to import | ||
| 3 | </h3> | ||
| 4 | <div class="flex-container flexFlowColumn justifyLeft"> | ||
| 5 | {{#each sections}} | ||
| 6 | {{#with this}} | ||
| 7 | <label class="checkbox_label"> | ||
| 8 | <input type="checkbox" value="{{key}}" checked> | ||
| 9 | <span data-i18n="{{name}}">{{name}}</span> | ||
| 10 | {{#if preset}} | ||
| 11 | <span>–</span> | ||
| 12 | <small>{{preset}}</small> | ||
| 13 | {{/if}} | ||
| 14 | </label> | ||
| 15 | {{/with}} | ||
| 16 | {{/each}} | ||
| 17 | </div> | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | <h3> | ||
| 2 | This instruct template also contains a system prompt. | ||
| 3 | </h3> | ||
| 4 | <div> | ||
| 5 | Would you like to migrate the system prompt from the template? | ||
| 6 | </div> | ||
| 7 | {{#if existing}} | ||
| 8 | <div class="marginTopBot5"> | ||
| 9 | <b>Note:</b> | ||
| 10 | <span>you already have this prompt saved as:</span> | ||
| 11 | <span>{{existing}}</span> | ||
| 12 | </div> | ||
| 13 | {{/if}} | ||
| 14 | <div class="justifyLeft marginTop5"> | ||
| 15 | <div> | ||
| 16 | <small> | ||
| 17 | <b>"Yes"</b> – The prompt will be imported and selected as a current system prompt. | ||
| 18 | </small> | ||
| 19 | |||
| 20 | </div> | ||
| 21 | <div> | ||
| 22 | <small> | ||
| 23 | <b>"No"</b> – The prompt will be ignored, no changes to the current system prompt. | ||
| 24 | </small> | ||
| 25 | </div> | ||
| 26 | </div> | ||
| 27 | <textarea class="wide100p textarea_compact" rows="10">{{prompt}}</textarea> | ||
| @@ -41,11 +41,6 @@ | |||
| 41 | SillyTavern Documentation Site | 41 | SillyTavern Documentation Site |
| 42 | </a> | 42 | </a> |
| 43 | </li> | 43 | </li> |
| 44 | <li> | ||
| 45 | <a target="_blank" href="https://docs.sillytavern.app/extras/installation/" data-i18n="Extras Installation Guide"> | ||
| 46 | Extras Installation Guide | ||
| 47 | </a> | ||
| 48 | </li> | ||
| 49 | </ul> | 44 | </ul> |
| 50 | 45 | ||
| 51 | <hr> | 46 | <hr> |
| @@ -15,7 +15,7 @@ import { BIAS_CACHE, createNewLogitBiasEntry, displayLogitBias, getLogitBiasList | |||
| 15 | import { power_user, registerDebugFunction } from './power-user.js'; | 15 | import { power_user, registerDebugFunction } from './power-user.js'; |
| 16 | import { getEventSourceStream } from './sse-stream.js'; | 16 | import { getEventSourceStream } from './sse-stream.js'; |
| 17 | import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer } from './textgen-models.js'; | 17 | import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer } from './textgen-models.js'; |
| 18 | import { SENTENCEPIECE_TOKENIZERS, TEXTGEN_TOKENIZERS, getTextTokens, tokenizers } from './tokenizers.js'; | 18 | import { ENCODE_TOKENIZERS, TEXTGEN_TOKENIZERS, getTextTokens, tokenizers } from './tokenizers.js'; |
| 19 | import { getSortableDelay, onlyUnique } from './utils.js'; | 19 | import { getSortableDelay, onlyUnique } from './utils.js'; |
| 20 | 20 | ||
| 21 | export { | 21 | export { |
| @@ -353,7 +353,7 @@ function getTokenizerForTokenIds() { | |||
| 353 | return tokenizers.API_CURRENT; | 353 | return tokenizers.API_CURRENT; |
| 354 | } | 354 | } |
| 355 | 355 | ||
| 356 | if (SENTENCEPIECE_TOKENIZERS.includes(power_user.tokenizer)) { | 356 | if (ENCODE_TOKENIZERS.includes(power_user.tokenizer)) { |
| 357 | return power_user.tokenizer; | 357 | return power_user.tokenizer; |
| 358 | } | 358 | } |
| 359 | 359 | ||
| @@ -1201,9 +1201,9 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, | |||
| 1201 | 'frequency_penalty': settings.freq_pen, | 1201 | 'frequency_penalty': settings.freq_pen, |
| 1202 | 'presence_penalty': settings.presence_pen, | 1202 | 'presence_penalty': settings.presence_pen, |
| 1203 | 'repetition_penalty': settings.rep_pen, | 1203 | 'repetition_penalty': settings.rep_pen, |
| 1204 | 'seed': settings.seed, | 1204 | 'seed': settings.seed >= 0 ? settings.seed : undefined, |
| 1205 | 'stop': getStoppingStrings(isImpersonate, isContinue), | 1205 | 'stop': getStoppingStrings(isImpersonate, isContinue), |
| 1206 | 'temperature': settings.temp, | 1206 | 'temperature': dynatemp ? (settings.min_temp + settings.max_temp) / 2 : settings.temp, |
| 1207 | 'temperature_last': settings.temperature_last, | 1207 | 'temperature_last': settings.temperature_last, |
| 1208 | 'top_p': settings.top_p, | 1208 | 'top_p': settings.top_p, |
| 1209 | 'top_k': settings.top_k, | 1209 | 'top_k': settings.top_k, |
| @@ -1223,6 +1223,12 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, | |||
| 1223 | 'guided_json': settings.json_schema, | 1223 | 'guided_json': settings.json_schema, |
| 1224 | 'early_stopping': false, // hacks | 1224 | 'early_stopping': false, // hacks |
| 1225 | 'include_stop_str_in_output': false, | 1225 | 'include_stop_str_in_output': false, |
| 1226 | 'dynatemp_min': dynatemp ? settings.min_temp : undefined, | ||
| 1227 | 'dynatemp_max': dynatemp ? settings.max_temp : undefined, | ||
| 1228 | 'dynatemp_exponent': dynatemp ? settings.dynatemp_exponent : undefined, | ||
| 1229 | 'xtc_threshold': settings.xtc_threshold, | ||
| 1230 | 'xtc_probability': settings.xtc_probability, | ||
| 1231 | 'custom_token_bans': toIntArray(banned_tokens), | ||
| 1226 | }; | 1232 | }; |
| 1227 | 1233 | ||
| 1228 | if (settings.type === OPENROUTER) { | 1234 | if (settings.type === OPENROUTER) { |
| @@ -10,7 +10,8 @@ import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, o | |||
| 10 | const { OOBA, TABBY, KOBOLDCPP, VLLM, APHRODITE, LLAMACPP, OPENROUTER, DREAMGEN } = textgen_types; | 10 | const { OOBA, TABBY, KOBOLDCPP, VLLM, APHRODITE, LLAMACPP, OPENROUTER, DREAMGEN } = textgen_types; |
| 11 | 11 | ||
| 12 | export const CHARACTERS_PER_TOKEN_RATIO = 3.35; | 12 | export const CHARACTERS_PER_TOKEN_RATIO = 3.35; |
| 13 | const TOKENIZER_WARNING_KEY = 'tokenizationWarningShown'; | 13 | export const TOKENIZER_WARNING_KEY = 'tokenizationWarningShown'; |
| 14 | export const TOKENIZER_SUPPORTED_KEY = 'tokenizationSupported'; | ||
| 14 | 15 | ||
| 15 | export const tokenizers = { | 16 | export const tokenizers = { |
| 16 | NONE: 0, | 17 | NONE: 0, |
| @@ -30,21 +31,27 @@ export const tokenizers = { | |||
| 30 | JAMBA: 14, | 31 | JAMBA: 14, |
| 31 | QWEN2: 15, | 32 | QWEN2: 15, |
| 32 | COMMAND_R: 16, | 33 | COMMAND_R: 16, |
| 34 | NEMO: 17, | ||
| 33 | BEST_MATCH: 99, | 35 | BEST_MATCH: 99, |
| 34 | }; | 36 | }; |
| 35 | 37 | ||
| 36 | export const SENTENCEPIECE_TOKENIZERS = [ | 38 | // A list of local tokenizers that support encoding and decoding token ids. |
| 39 | export const ENCODE_TOKENIZERS = [ | ||
| 37 | tokenizers.LLAMA, | 40 | tokenizers.LLAMA, |
| 38 | tokenizers.MISTRAL, | 41 | tokenizers.MISTRAL, |
| 39 | tokenizers.YI, | 42 | tokenizers.YI, |
| 40 | tokenizers.LLAMA3, | 43 | tokenizers.LLAMA3, |
| 41 | tokenizers.GEMMA, | 44 | tokenizers.GEMMA, |
| 42 | tokenizers.JAMBA, | 45 | tokenizers.JAMBA, |
| 46 | tokenizers.QWEN2, | ||
| 47 | tokenizers.COMMAND_R, | ||
| 48 | tokenizers.NEMO, | ||
| 43 | // uncomment when NovelAI releases Kayra and Clio weights, lol | 49 | // uncomment when NovelAI releases Kayra and Clio weights, lol |
| 44 | //tokenizers.NERD, | 50 | //tokenizers.NERD, |
| 45 | //tokenizers.NERD2, | 51 | //tokenizers.NERD2, |
| 46 | ]; | 52 | ]; |
| 47 | 53 | ||
| 54 | // A list of Text Completion sources that support remote tokenization. | ||
| 48 | export const TEXTGEN_TOKENIZERS = [OOBA, TABBY, KOBOLDCPP, LLAMACPP, VLLM, APHRODITE]; | 55 | export const TEXTGEN_TOKENIZERS = [OOBA, TABBY, KOBOLDCPP, LLAMACPP, VLLM, APHRODITE]; |
| 49 | 56 | ||
| 50 | const TOKENIZER_URLS = { | 57 | const TOKENIZER_URLS = { |
| @@ -117,6 +124,11 @@ const TOKENIZER_URLS = { | |||
| 117 | decode: '/api/tokenizers/command-r/decode', | 124 | decode: '/api/tokenizers/command-r/decode', |
| 118 | count: '/api/tokenizers/command-r/encode', | 125 | count: '/api/tokenizers/command-r/encode', |
| 119 | }, | 126 | }, |
| 127 | [tokenizers.NEMO]: { | ||
| 128 | encode: '/api/tokenizers/nemo/encode', | ||
| 129 | decode: '/api/tokenizers/nemo/decode', | ||
| 130 | count: '/api/tokenizers/nemo/encode', | ||
| 131 | }, | ||
| 120 | [tokenizers.API_TEXTGENERATIONWEBUI]: { | 132 | [tokenizers.API_TEXTGENERATIONWEBUI]: { |
| 121 | encode: '/api/tokenizers/remote/textgenerationwebui/encode', | 133 | encode: '/api/tokenizers/remote/textgenerationwebui/encode', |
| 122 | count: '/api/tokenizers/remote/textgenerationwebui/encode', | 134 | count: '/api/tokenizers/remote/textgenerationwebui/encode', |
| @@ -262,6 +274,9 @@ export function getTokenizerBestMatch(forApi) { | |||
| 262 | if (nai_settings.model_novel.includes('kayra')) { | 274 | if (nai_settings.model_novel.includes('kayra')) { |
| 263 | return tokenizers.NERD2; | 275 | return tokenizers.NERD2; |
| 264 | } | 276 | } |
| 277 | if (nai_settings.model_novel.includes('erato')) { | ||
| 278 | return tokenizers.LLAMA3; | ||
| 279 | } | ||
| 265 | } | 280 | } |
| 266 | if (forApi === 'kobold' || forApi === 'textgenerationwebui' || forApi === 'koboldhorde') { | 281 | if (forApi === 'kobold' || forApi === 'textgenerationwebui' || forApi === 'koboldhorde') { |
| 267 | // Try to use the API tokenizer if possible: | 282 | // Try to use the API tokenizer if possible: |
| @@ -269,8 +284,9 @@ export function getTokenizerBestMatch(forApi) { | |||
| 269 | // - Kobold must pass a version check | 284 | // - Kobold must pass a version check |
| 270 | // - Tokenizer haven't reported an error previously | 285 | // - Tokenizer haven't reported an error previously |
| 271 | const hasTokenizerError = sessionStorage.getItem(TOKENIZER_WARNING_KEY); | 286 | const hasTokenizerError = sessionStorage.getItem(TOKENIZER_WARNING_KEY); |
| 287 | const hasValidEndpoint = sessionStorage.getItem(TOKENIZER_SUPPORTED_KEY); | ||
| 272 | const isConnected = online_status !== 'no_connection'; | 288 | const isConnected = online_status !== 'no_connection'; |
| 273 | const isTokenizerSupported = TEXTGEN_TOKENIZERS.includes(textgen_settings.type); | 289 | const isTokenizerSupported = TEXTGEN_TOKENIZERS.includes(textgen_settings.type) && (textgen_settings.type !== OOBA || hasValidEndpoint); |
| 274 | 290 | ||
| 275 | if (!hasTokenizerError && isConnected) { | 291 | if (!hasTokenizerError && isConnected) { |
| 276 | if (forApi === 'kobold' && kai_flags.can_use_tokenization) { | 292 | if (forApi === 'kobold' && kai_flags.can_use_tokenization) { |
| @@ -531,6 +547,7 @@ export function getTokenizerModel() { | |||
| 531 | const jambaTokenizer = 'jamba'; | 547 | const jambaTokenizer = 'jamba'; |
| 532 | const qwen2Tokenizer = 'qwen2'; | 548 | const qwen2Tokenizer = 'qwen2'; |
| 533 | const commandRTokenizer = 'command-r'; | 549 | const commandRTokenizer = 'command-r'; |
| 550 | const nemoTokenizer = 'nemo'; | ||
| 534 | 551 | ||
| 535 | // Assuming no one would use it for different models.. right? | 552 | // Assuming no one would use it for different models.. right? |
| 536 | if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) { | 553 | if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) { |
| @@ -624,6 +641,9 @@ export function getTokenizerModel() { | |||
| 624 | } | 641 | } |
| 625 | 642 | ||
| 626 | if (oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) { | 643 | if (oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) { |
| 644 | if (oai_settings.mistralai_model.includes('nemo') || oai_settings.mistralai_model.includes('pixtral')) { | ||
| 645 | return nemoTokenizer; | ||
| 646 | } | ||
| 627 | return mistralTokenizer; | 647 | return mistralTokenizer; |
| 628 | } | 648 | } |
| 629 | 649 | ||
| @@ -908,15 +928,20 @@ function countTokensFromTextgenAPI(str, resolve) { | |||
| 908 | 928 | ||
| 909 | function apiFailureTokenCount(str) { | 929 | function apiFailureTokenCount(str) { |
| 910 | console.error('Error counting tokens'); | 930 | console.error('Error counting tokens'); |
| 931 | let shouldTryAgain = false; | ||
| 911 | 932 | ||
| 912 | if (!sessionStorage.getItem(TOKENIZER_WARNING_KEY)) { | 933 | if (!sessionStorage.getItem(TOKENIZER_WARNING_KEY)) { |
| 913 | toastr.warning( | 934 | const bestMatchBefore = getTokenizerBestMatch(main_api); |
| 914 | 'Your selected API doesn\'t support the tokenization endpoint. Using estimated counts.', | ||
| 915 | 'Error counting tokens', | ||
| 916 | { timeOut: 10000, preventDuplicates: true }, | ||
| 917 | ); | ||
| 918 | |||
| 919 | sessionStorage.setItem(TOKENIZER_WARNING_KEY, String(true)); | 935 | sessionStorage.setItem(TOKENIZER_WARNING_KEY, String(true)); |
| 936 | const bestMatchAfter = getTokenizerBestMatch(main_api); | ||
| 937 | if ([tokenizers.API_TEXTGENERATIONWEBUI, tokenizers.API_KOBOLD].includes(bestMatchBefore) && bestMatchBefore !== bestMatchAfter) { | ||
| 938 | shouldTryAgain = true; | ||
| 939 | } | ||
| 940 | } | ||
| 941 | |||
| 942 | // Only try again if we guarantee not to be looped by the same error | ||
| 943 | if (shouldTryAgain && power_user.tokenizer === tokenizers.BEST_MATCH) { | ||
| 944 | return getTokenCount(str); | ||
| 920 | } | 945 | } |
| 921 | 946 | ||
| 922 | return guesstimate(str); | 947 | return guesstimate(str); |
| @@ -607,12 +607,11 @@ export function sortByCssOrder(a, b) { | |||
| 607 | /** | 607 | /** |
| 608 | * Trims a string to the end of a nearest sentence. | 608 | * Trims a string to the end of a nearest sentence. |
| 609 | * @param {string} input The string to trim. | 609 | * @param {string} input The string to trim. |
| 610 | * @param {boolean} include_newline Whether to include a newline character in the trimmed string. | ||
| 611 | * @returns {string} The trimmed string. | 610 | * @returns {string} The trimmed string. |
| 612 | * @example | 611 | * @example |
| 613 | * trimToEndSentence('Hello, world! I am from'); // 'Hello, world!' | 612 | * trimToEndSentence('Hello, world! I am from'); // 'Hello, world!' |
| 614 | */ | 613 | */ |
| 615 | export function trimToEndSentence(input, include_newline = false) { | 614 | export function trimToEndSentence(input) { |
| 616 | if (!input) { | 615 | if (!input) { |
| 617 | return ''; | 616 | return ''; |
| 618 | } | 617 | } |
| @@ -633,11 +632,6 @@ export function trimToEndSentence(input, include_newline = false) { | |||
| 633 | } | 632 | } |
| 634 | break; | 633 | break; |
| 635 | } | 634 | } |
| 636 | |||
| 637 | if (include_newline && char === '\n') { | ||
| 638 | last = i; | ||
| 639 | break; | ||
| 640 | } | ||
| 641 | } | 635 | } |
| 642 | 636 | ||
| 643 | if (last === -1) { | 637 | if (last === -1) { |
| @@ -1908,13 +1902,13 @@ export function select2ChoiceClickSubscribe(control, action, { buttonStyle = fal | |||
| 1908 | * @returns {string} The html representation of the highlighted regex | 1902 | * @returns {string} The html representation of the highlighted regex |
| 1909 | */ | 1903 | */ |
| 1910 | export function highlightRegex(regexStr) { | 1904 | export function highlightRegex(regexStr) { |
| 1911 | // Function to escape HTML special characters for safety | 1905 | // Function to escape special characters for safety or readability |
| 1912 | const escapeHtml = (str) => str.replace(/[&<>"']/g, match => ({ | 1906 | const escape = (str) => str.replace(/[&<>"'\x01]/g, match => ({ |
| 1913 | '&': '&', '<': '<', '>': '>', '"': '"', '\'': ''', | 1907 | '&': '&', '<': '<', '>': '>', '"': '"', '\'': ''', '\x01': '\\x01', |
| 1914 | })[match]); | 1908 | })[match]); |
| 1915 | 1909 | ||
| 1916 | // Replace special characters with their HTML-escaped forms | 1910 | // Replace special characters with their escaped forms |
| 1917 | regexStr = escapeHtml(regexStr); | 1911 | regexStr = escape(regexStr); |
| 1918 | 1912 | ||
| 1919 | // Patterns that we want to highlight only if they are not escaped | 1913 | // Patterns that we want to highlight only if they are not escaped |
| 1920 | function getPatterns() { | 1914 | function getPatterns() { |
| @@ -217,8 +217,9 @@ class WorldInfoBuffer { | |||
| 217 | depth = MAX_SCAN_DEPTH; | 217 | depth = MAX_SCAN_DEPTH; |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | const JOINER = '\n\x01'; | 220 | const MATCHER = '\x01'; |
| 221 | let result = this.#depthBuffer.slice(this.#startDepth, depth).join(JOINER); | 221 | const JOINER = '\n' + MATCHER; |
| 222 | let result = MATCHER + this.#depthBuffer.slice(this.#startDepth, depth).join(JOINER); | ||
| 222 | 223 | ||
| 223 | if (this.#injectBuffer.length > 0) { | 224 | if (this.#injectBuffer.length > 0) { |
| 224 | result += JOINER + this.#injectBuffer.join(JOINER); | 225 | result += JOINER + this.#injectBuffer.join(JOINER); |
| @@ -2949,16 +2950,39 @@ async function getWorldEntry(name, data, entry) { | |||
| 2949 | preventRecursionInput.prop('checked', entry.preventRecursion).trigger('input'); | 2950 | preventRecursionInput.prop('checked', entry.preventRecursion).trigger('input'); |
| 2950 | 2951 | ||
| 2951 | // delay until recursion | 2952 | // delay until recursion |
| 2953 | // delay until recursion level | ||
| 2952 | const delayUntilRecursionInput = template.find('input[name="delay_until_recursion"]'); | 2954 | const delayUntilRecursionInput = template.find('input[name="delay_until_recursion"]'); |
| 2953 | delayUntilRecursionInput.data('uid', entry.uid); | 2955 | delayUntilRecursionInput.data('uid', entry.uid); |
| 2956 | const delayUntilRecursionLevelInput = template.find('input[name="delayUntilRecursionLevel"]'); | ||
| 2957 | delayUntilRecursionLevelInput.data('uid', entry.uid); | ||
| 2954 | delayUntilRecursionInput.on('input', async function () { | 2958 | delayUntilRecursionInput.on('input', async function () { |
| 2955 | const uid = $(this).data('uid'); | 2959 | const uid = $(this).data('uid'); |
| 2956 | const value = $(this).prop('checked'); | 2960 | const toggled = $(this).prop('checked'); |
| 2961 | |||
| 2962 | // If the value contains a number, we'll take that one (set by the level input), otherwise we can use true/false switch | ||
| 2963 | const value = toggled ? data.entries[uid].delayUntilRecursion || true : false; | ||
| 2964 | |||
| 2965 | if (!toggled) delayUntilRecursionLevelInput.val(''); | ||
| 2966 | |||
| 2957 | data.entries[uid].delayUntilRecursion = value; | 2967 | data.entries[uid].delayUntilRecursion = value; |
| 2958 | setWIOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion); | 2968 | setWIOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion); |
| 2959 | await saveWorldInfo(name, data); | 2969 | await saveWorldInfo(name, data); |
| 2960 | }); | 2970 | }); |
| 2961 | delayUntilRecursionInput.prop('checked', entry.delayUntilRecursion).trigger('input'); | 2971 | delayUntilRecursionInput.prop('checked', entry.delayUntilRecursion).trigger('input'); |
| 2972 | delayUntilRecursionLevelInput.on('input', async function () { | ||
| 2973 | const uid = $(this).data('uid'); | ||
| 2974 | const content = $(this).val(); | ||
| 2975 | const value = content === '' ? (typeof data.entries[uid].delayUntilRecursion === 'boolean' ? data.entries[uid].delayUntilRecursion : true) | ||
| 2976 | : content === 1 ? true | ||
| 2977 | : !isNaN(Number(content)) ? Number(content) | ||
| 2978 | : false; | ||
| 2979 | |||
| 2980 | data.entries[uid].delayUntilRecursion = value; | ||
| 2981 | setWIOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion); | ||
| 2982 | await saveWorldInfo(name, data); | ||
| 2983 | }); | ||
| 2984 | // No need to retrigger inpout event, we'll just set the curret current value. It was edited/saved above already | ||
| 2985 | delayUntilRecursionLevelInput.val(['number', 'string'].includes(typeof entry.delayUntilRecursion) ? entry.delayUntilRecursion : '').trigger('input'); | ||
| 2962 | 2986 | ||
| 2963 | // duplicate button | 2987 | // duplicate button |
| 2964 | const duplicateButton = template.find('.duplicate_entry_button'); | 2988 | const duplicateButton = template.find('.duplicate_entry_button'); |
| @@ -3257,7 +3281,7 @@ export const newWorldInfoEntryDefinition = { | |||
| 3257 | disable: { default: false, type: 'boolean' }, | 3281 | disable: { default: false, type: 'boolean' }, |
| 3258 | excludeRecursion: { default: false, type: 'boolean' }, | 3282 | excludeRecursion: { default: false, type: 'boolean' }, |
| 3259 | preventRecursion: { default: false, type: 'boolean' }, | 3283 | preventRecursion: { default: false, type: 'boolean' }, |
| 3260 | delayUntilRecursion: { default: false, type: 'boolean' }, | 3284 | delayUntilRecursion: { default: 0, type: 'number' }, |
| 3261 | probability: { default: 100, type: 'number' }, | 3285 | probability: { default: 100, type: 'number' }, |
| 3262 | useProbability: { default: true, type: 'boolean' }, | 3286 | useProbability: { default: true, type: 'boolean' }, |
| 3263 | depth: { default: DEFAULT_DEPTH, type: 'number' }, | 3287 | depth: { default: DEFAULT_DEPTH, type: 'number' }, |
| @@ -3696,6 +3720,7 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 3696 | } | 3720 | } |
| 3697 | } | 3721 | } |
| 3698 | 3722 | ||
| 3723 | /** @type {scan_state} */ | ||
| 3699 | let scanState = scan_state.INITIAL; | 3724 | let scanState = scan_state.INITIAL; |
| 3700 | let token_budget_overflowed = false; | 3725 | let token_budget_overflowed = false; |
| 3701 | let count = 0; | 3726 | let count = 0; |
| @@ -3720,6 +3745,17 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 3720 | return { worldInfoBefore: '', worldInfoAfter: '', WIDepthEntries: [], EMEntries: [], allActivatedEntries: new Set() }; | 3745 | return { worldInfoBefore: '', worldInfoAfter: '', WIDepthEntries: [], EMEntries: [], allActivatedEntries: new Set() }; |
| 3721 | } | 3746 | } |
| 3722 | 3747 | ||
| 3748 | /** @type {number[]} Represents the delay levels for entries that are delayed until recursion */ | ||
| 3749 | const availableRecursionDelayLevels = [...new Set(sortedEntries | ||
| 3750 | .filter(entry => entry.delayUntilRecursion) | ||
| 3751 | .map(entry => entry.delayUntilRecursion === true ? 1 : entry.delayUntilRecursion), | ||
| 3752 | )].sort((a, b) => a - b); | ||
| 3753 | // Already preset with the first level | ||
| 3754 | let currentRecursionDelayLevel = availableRecursionDelayLevels.shift() ?? 0; | ||
| 3755 | if (currentRecursionDelayLevel > 0 && availableRecursionDelayLevels.length) { | ||
| 3756 | console.debug('[WI] Preparing first delayed recursion level', currentRecursionDelayLevel, '. Still delayed:', availableRecursionDelayLevels); | ||
| 3757 | } | ||
| 3758 | |||
| 3723 | console.debug(`[WI] --- SEARCHING ENTRIES (on ${sortedEntries.length} entries) ---`); | 3759 | console.debug(`[WI] --- SEARCHING ENTRIES (on ${sortedEntries.length} entries) ---`); |
| 3724 | 3760 | ||
| 3725 | while (scanState) { | 3761 | while (scanState) { |
| @@ -3732,7 +3768,8 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 3732 | // Track how many times the loop has run. May be useful for debugging. | 3768 | // Track how many times the loop has run. May be useful for debugging. |
| 3733 | count++; | 3769 | count++; |
| 3734 | 3770 | ||
| 3735 | console.debug(`[WI] Loop #${count}. Search state`, Object.entries(scan_state).find(x => x[1] === scanState)); | 3771 | console.debug(`[WI] --- LOOP #${count} START ---`); |
| 3772 | console.debug('[WI] Scan state', Object.entries(scan_state).find(x => x[1] === scanState)); | ||
| 3736 | 3773 | ||
| 3737 | // Until decided otherwise, we set the loop to stop scanning after this | 3774 | // Until decided otherwise, we set the loop to stop scanning after this |
| 3738 | let nextScanState = scan_state.NONE; | 3775 | let nextScanState = scan_state.NONE; |
| @@ -3811,6 +3848,11 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 3811 | continue; | 3848 | continue; |
| 3812 | } | 3849 | } |
| 3813 | 3850 | ||
| 3851 | if (scanState === scan_state.RECURSION && entry.delayUntilRecursion && entry.delayUntilRecursion > currentRecursionDelayLevel && !isSticky) { | ||
| 3852 | log('suppressed by delay until recursion level', entry.delayUntilRecursion, '. Currently', currentRecursionDelayLevel); | ||
| 3853 | continue; | ||
| 3854 | } | ||
| 3855 | |||
| 3814 | if (scanState === scan_state.RECURSION && world_info_recursive && entry.excludeRecursion && !isSticky) { | 3856 | if (scanState === scan_state.RECURSION && world_info_recursive && entry.excludeRecursion && !isSticky) { |
| 3815 | log('suppressed by exclude recursion'); | 3857 | log('suppressed by exclude recursion'); |
| 3816 | continue; | 3858 | continue; |
| @@ -3949,6 +3991,8 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 3949 | filterByInclusionGroups(newEntries, allActivatedEntries, buffer, scanState, timedEffects); | 3991 | filterByInclusionGroups(newEntries, allActivatedEntries, buffer, scanState, timedEffects); |
| 3950 | 3992 | ||
| 3951 | console.debug('[WI] --- PROBABILITY CHECKS ---'); | 3993 | console.debug('[WI] --- PROBABILITY CHECKS ---'); |
| 3994 | !newEntries.length && console.debug('[WI] No probability checks to do'); | ||
| 3995 | |||
| 3952 | for (const entry of newEntries) { | 3996 | for (const entry of newEntries) { |
| 3953 | function verifyProbability() { | 3997 | function verifyProbability() { |
| 3954 | // If we don't need to roll, it's always true | 3998 | // If we don't need to roll, it's always true |
| @@ -3984,6 +4028,7 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 3984 | newContent += `${entry.content}\n`; | 4028 | newContent += `${entry.content}\n`; |
| 3985 | 4029 | ||
| 3986 | if ((textToScanTokens + (await getTokenCountAsync(newContent))) >= budget) { | 4030 | if ((textToScanTokens + (await getTokenCountAsync(newContent))) >= budget) { |
| 4031 | console.debug('[WI] --- BUDGET OVERFLOW CHECK ---'); | ||
| 3987 | if (world_info_overflow_alert) { | 4032 | if (world_info_overflow_alert) { |
| 3988 | console.warn(`[WI] budget of ${budget} reached, stopping after ${allActivatedEntries.size} entries`); | 4033 | console.warn(`[WI] budget of ${budget} reached, stopping after ${allActivatedEntries.size} entries`); |
| 3989 | toastr.warning(`World info budget reached after ${allActivatedEntries.size} entries.`, 'World Info'); | 4034 | toastr.warning(`World info budget reached after ${allActivatedEntries.size} entries.`, 'World Info'); |
| @@ -4001,23 +4046,31 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 4001 | const successfulNewEntries = newEntries.filter(x => !failedProbabilityChecks.has(x)); | 4046 | const successfulNewEntries = newEntries.filter(x => !failedProbabilityChecks.has(x)); |
| 4002 | const successfulNewEntriesForRecursion = successfulNewEntries.filter(x => !x.preventRecursion); | 4047 | const successfulNewEntriesForRecursion = successfulNewEntries.filter(x => !x.preventRecursion); |
| 4003 | 4048 | ||
| 4049 | console.debug(`[WI] --- LOOP #${count} RESULT ---`); | ||
| 4004 | if (!newEntries.length) { | 4050 | if (!newEntries.length) { |
| 4005 | console.debug('[WI] No new entries activated, stopping'); | 4051 | console.debug('[WI] No new entries activated.'); |
| 4006 | } else if (!successfulNewEntries.length) { | 4052 | } else if (!successfulNewEntries.length) { |
| 4007 | console.debug('[WI] Probability checks failed for all activated entries, stopping'); | 4053 | console.debug('[WI] Probability checks failed for all activated entries. No new entries activated.'); |
| 4008 | } else { | 4054 | } else { |
| 4009 | console.debug(`[WI] Successfully activated ${successfulNewEntries.length} new entries to prompt. ${allActivatedEntries.size} total entries activated.`, successfulNewEntries); | 4055 | console.debug(`[WI] Successfully activated ${successfulNewEntries.length} new entries to prompt. ${allActivatedEntries.size} total entries activated.`, successfulNewEntries); |
| 4010 | } | 4056 | } |
| 4011 | 4057 | ||
| 4058 | function logNextState(...args) { | ||
| 4059 | args.length && console.debug(args.shift(), ...args); | ||
| 4060 | console.debug('[WI] Setting scan state', Object.entries(scan_state).find(x => x[1] === scanState)); | ||
| 4061 | } | ||
| 4062 | |||
| 4012 | // After processing and rolling entries is done, see if we should continue with normal recursion | 4063 | // After processing and rolling entries is done, see if we should continue with normal recursion |
| 4013 | if (world_info_recursive && !token_budget_overflowed && successfulNewEntriesForRecursion.length) { | 4064 | if (world_info_recursive && !token_budget_overflowed && successfulNewEntriesForRecursion.length) { |
| 4014 | nextScanState = scan_state.RECURSION; | 4065 | nextScanState = scan_state.RECURSION; |
| 4066 | logNextState('[WI] Found', successfulNewEntriesForRecursion.length, 'new entries for recursion'); | ||
| 4015 | } | 4067 | } |
| 4016 | 4068 | ||
| 4017 | // If we are inside min activations scan, and we have recursive buffer, we should do a recursive scan before increasing the buffer again | 4069 | // If we are inside min activations scan, and we have recursive buffer, we should do a recursive scan before increasing the buffer again |
| 4018 | // There might be recurse-trigger-able entries that match the buffer, so we need to check that | 4070 | // There might be recurse-trigger-able entries that match the buffer, so we need to check that |
| 4019 | if (world_info_recursive && !token_budget_overflowed && scanState === scan_state.MIN_ACTIVATIONS && buffer.hasRecurse()) { | 4071 | if (world_info_recursive && !token_budget_overflowed && scanState === scan_state.MIN_ACTIVATIONS && buffer.hasRecurse()) { |
| 4020 | nextScanState = scan_state.RECURSION; | 4072 | nextScanState = scan_state.RECURSION; |
| 4073 | logNextState('[WI] Min Activations run done, whill will always be followed by a recursive scan'); | ||
| 4021 | } | 4074 | } |
| 4022 | 4075 | ||
| 4023 | // If scanning is planned to stop, but min activations is set and not satisfied, check if we should continue | 4076 | // If scanning is planned to stop, but min activations is set and not satisfied, check if we should continue |
| @@ -4031,14 +4084,21 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 4031 | ) || (buffer.getDepth() > chat.length); | 4084 | ) || (buffer.getDepth() > chat.length); |
| 4032 | 4085 | ||
| 4033 | if (!over_max) { | 4086 | if (!over_max) { |
| 4034 | console.debug(`[WI] Min activations not reached (${allActivatedEntries.size}/${world_info_min_activations}), advancing depth to ${buffer.getDepth() + 1} and checking again`); | ||
| 4035 | nextScanState = scan_state.MIN_ACTIVATIONS; // loop | 4087 | nextScanState = scan_state.MIN_ACTIVATIONS; // loop |
| 4088 | logNextState(`[WI] Min activations not reached (${allActivatedEntries.size}/${world_info_min_activations}), advancing depth to ${buffer.getDepth() + 1}, starting another scan`); | ||
| 4036 | buffer.advanceScan(); | 4089 | buffer.advanceScan(); |
| 4037 | } else { | 4090 | } else { |
| 4038 | console.debug(`[WI] Min activations not reached (${allActivatedEntries.size}/${world_info_min_activations}), but reached on of depth. Stopping`); | 4091 | console.debug(`[WI] Min activations not reached (${allActivatedEntries.size}/${world_info_min_activations}), but reached on of depth. Stopping`); |
| 4039 | } | 4092 | } |
| 4040 | } | 4093 | } |
| 4041 | 4094 | ||
| 4095 | // If the scan is done, but we still have open "delay until recursion" levels, we should continue with the next one | ||
| 4096 | if (nextScanState === scan_state.NONE && availableRecursionDelayLevels.length) { | ||
| 4097 | nextScanState = scan_state.RECURSION; | ||
| 4098 | currentRecursionDelayLevel = availableRecursionDelayLevels.shift(); | ||
| 4099 | logNextState('[WI] Open delayed recursion levels left. Preparing next delayed recursion level', currentRecursionDelayLevel, '. Still delayed:', availableRecursionDelayLevels); | ||
| 4100 | } | ||
| 4101 | |||
| 4042 | // Final check if we should really continue scan, and extend the current WI recurse buffer | 4102 | // Final check if we should really continue scan, and extend the current WI recurse buffer |
| 4043 | scanState = nextScanState; | 4103 | scanState = nextScanState; |
| 4044 | if (scanState) { | 4104 | if (scanState) { |
| @@ -4046,6 +4106,8 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 4046 | .map(x => x.content).join('\n'); | 4106 | .map(x => x.content).join('\n'); |
| 4047 | buffer.addRecurse(text); | 4107 | buffer.addRecurse(text); |
| 4048 | allActivatedText = (text + '\n' + allActivatedText); | 4108 | allActivatedText = (text + '\n' + allActivatedText); |
| 4109 | } else { | ||
| 4110 | logNextState('[WI] Scan done. No new entries to prompt. Stopping.'); | ||
| 4049 | } | 4111 | } |
| 4050 | } | 4112 | } |
| 4051 | 4113 | ||
| @@ -4072,10 +4134,10 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 4072 | 4134 | ||
| 4073 | switch (entry.position) { | 4135 | switch (entry.position) { |
| 4074 | case world_info_position.before: | 4136 | case world_info_position.before: |
| 4075 | WIBeforeEntries.unshift(substituteParams(content)); | 4137 | WIBeforeEntries.unshift(content); |
| 4076 | break; | 4138 | break; |
| 4077 | case world_info_position.after: | 4139 | case world_info_position.after: |
| 4078 | WIAfterEntries.unshift(substituteParams(content)); | 4140 | WIAfterEntries.unshift(content); |
| 4079 | break; | 4141 | break; |
| 4080 | case world_info_position.EMTop: | 4142 | case world_info_position.EMTop: |
| 4081 | EMEntries.unshift( | 4143 | EMEntries.unshift( |
| @@ -2570,20 +2570,25 @@ input[type="file"] { | |||
| 2570 | /*#################################################################*/ | 2570 | /*#################################################################*/ |
| 2571 | 2571 | ||
| 2572 | select { | 2572 | select { |
| 2573 | 2573 | -moz-appearance: none; | |
| 2574 | padding: 3px 2px; | 2574 | -webkit-appearance: none; |
| 2575 | appearance: none; | ||
| 2576 | padding: 3px 5px; | ||
| 2575 | background-color: var(--black30a); | 2577 | background-color: var(--black30a); |
| 2576 | border: 1px solid var(--SmartThemeBorderColor); | 2578 | border: 1px solid var(--SmartThemeBorderColor); |
| 2577 | border-radius: 5px; | 2579 | border-radius: 5px; |
| 2578 | margin-bottom: 5px; | 2580 | margin-bottom: 5px; |
| 2579 | height: min-content; | 2581 | height: min-content; |
| 2582 | background-image: url('/img/down-arrow.svg'); | ||
| 2583 | background-repeat: no-repeat; | ||
| 2584 | background-position: right 6px center; | ||
| 2585 | background-size: 8px 5px; | ||
| 2580 | } | 2586 | } |
| 2581 | 2587 | ||
| 2582 | select option { | 2588 | select option { |
| 2583 | /* works to highlight selected/active option */ | 2589 | /* works to highlight selected/active option */ |
| 2584 | background-color: var(--white50a); | 2590 | background-color: var(--white50a); |
| 2585 | color: var(--black70a); | 2591 | color: var(--black70a); |
| 2586 | |||
| 2587 | } | 2592 | } |
| 2588 | 2593 | ||
| 2589 | select option:not(:checked) { | 2594 | select option:not(:checked) { |
| @@ -2625,14 +2630,6 @@ select option:not(:checked) { | |||
| 2625 | color: var(--active) !important; | 2630 | color: var(--active) !important; |
| 2626 | } | 2631 | } |
| 2627 | 2632 | ||
| 2628 | #context_set_default.default { | ||
| 2629 | color: var(--preferred) !important; | ||
| 2630 | } | ||
| 2631 | |||
| 2632 | #instruct_set_default.default { | ||
| 2633 | color: var(--preferred) !important; | ||
| 2634 | } | ||
| 2635 | |||
| 2636 | .displayBlock { | 2633 | .displayBlock { |
| 2637 | display: block !important; | 2634 | display: block !important; |
| 2638 | } | 2635 | } |
| @@ -3518,6 +3515,14 @@ grammarly-extension { | |||
| 3518 | column-gap: 20px; | 3515 | column-gap: 20px; |
| 3519 | } | 3516 | } |
| 3520 | 3517 | ||
| 3518 | .horde-model-description { | ||
| 3519 | -webkit-line-clamp: 3; | ||
| 3520 | line-clamp: 3; | ||
| 3521 | font-size: 0.9em; | ||
| 3522 | overflow: hidden; | ||
| 3523 | text-overflow: ellipsis; | ||
| 3524 | } | ||
| 3525 | |||
| 3521 | .drag-handle { | 3526 | .drag-handle { |
| 3522 | cursor: grab; | 3527 | cursor: grab; |
| 3523 | /* Make the drag handle not selectable in most browsers */ | 3528 | /* Make the drag handle not selectable in most browsers */ |
| @@ -5464,3 +5469,12 @@ body:not(.movingUI) .drawer-content.maximized { | |||
| 5464 | #AdvancedFormatting .autoSetHeight { | 5469 | #AdvancedFormatting .autoSetHeight { |
| 5465 | overflow-wrap: anywhere; | 5470 | overflow-wrap: anywhere; |
| 5466 | } | 5471 | } |
| 5472 | |||
| 5473 | #InstructSequencesColumn summary { | ||
| 5474 | font-size: 0.95em; | ||
| 5475 | cursor: pointer; | ||
| 5476 | } | ||
| 5477 | |||
| 5478 | #InstructSequencesColumn details:not(:last-of-type) { | ||
| 5479 | margin-bottom: 5px; | ||
| 5480 | } | ||
| @@ -610,6 +610,9 @@ app.use('/api/search', require('./src/endpoints/search').router); | |||
| 610 | // Ooba/OpenAI text completions | 610 | // Ooba/OpenAI text completions |
| 611 | app.use('/api/backends/text-completions', require('./src/endpoints/backends/text-completions').router); | 611 | app.use('/api/backends/text-completions', require('./src/endpoints/backends/text-completions').router); |
| 612 | 612 | ||
| 613 | // OpenRouter | ||
| 614 | app.use('/api/openrouter', require('./src/endpoints/openrouter').router); | ||
| 615 | |||
| 613 | // KoboldAI | 616 | // KoboldAI |
| 614 | app.use('/api/backends/kobold', require('./src/endpoints/backends/kobold').router); | 617 | app.use('/api/backends/kobold', require('./src/endpoints/backends/kobold').router); |
| 615 | 618 | ||
| @@ -929,6 +932,7 @@ async function verifySecuritySettings() { | |||
| 929 | userModule.initUserStorage(dataRoot) | 932 | userModule.initUserStorage(dataRoot) |
| 930 | .then(userModule.ensurePublicDirectoriesExist) | 933 | .then(userModule.ensurePublicDirectoriesExist) |
| 931 | .then(userModule.migrateUserData) | 934 | .then(userModule.migrateUserData) |
| 935 | .then(userModule.migrateSystemPrompts) | ||
| 932 | .then(verifySecuritySettings) | 936 | .then(verifySecuritySettings) |
| 933 | .then(preSetupTasks) | 937 | .then(preSetupTasks) |
| 934 | .finally(startServer); | 938 | .finally(startServer); |
| @@ -5,7 +5,6 @@ const PUBLIC_DIRECTORIES = { | |||
| 5 | extensions: 'public/scripts/extensions', | 5 | extensions: 'public/scripts/extensions', |
| 6 | }; | 6 | }; |
| 7 | 7 | ||
| 8 | const DEFAULT_AVATAR = '/img/ai4.png'; | ||
| 9 | const SETTINGS_FILE = 'settings.json'; | 8 | const SETTINGS_FILE = 'settings.json'; |
| 10 | 9 | ||
| 11 | /** | 10 | /** |
| @@ -42,6 +41,7 @@ const USER_DIRECTORY_TEMPLATE = Object.freeze({ | |||
| 42 | files: 'user/files', | 41 | files: 'user/files', |
| 43 | vectors: 'vectors', | 42 | vectors: 'vectors', |
| 44 | backups: 'backups', | 43 | backups: 'backups', |
| 44 | sysprompt: 'sysprompt', | ||
| 45 | }); | 45 | }); |
| 46 | 46 | ||
| 47 | /** | 47 | /** |
| @@ -422,7 +422,6 @@ const VLLM_KEYS = [ | |||
| 422 | 422 | ||
| 423 | module.exports = { | 423 | module.exports = { |
| 424 | DEFAULT_USER, | 424 | DEFAULT_USER, |
| 425 | DEFAULT_AVATAR, | ||
| 426 | SETTINGS_FILE, | 425 | SETTINGS_FILE, |
| 427 | PUBLIC_DIRECTORIES, | 426 | PUBLIC_DIRECTORIES, |
| 428 | USER_DIRECTORY_TEMPLATE, | 427 | USER_DIRECTORY_TEMPLATE, |
| @@ -186,6 +186,7 @@ router.post('/status', jsonParser, async function (request, response) { | |||
| 186 | 186 | ||
| 187 | const modelName = modelInfo?.model_name; | 187 | const modelName = modelInfo?.model_name; |
| 188 | result = modelName || result; | 188 | result = modelName || result; |
| 189 | response.setHeader('x-supports-tokenization', 'true'); | ||
| 189 | } | 190 | } |
| 190 | } catch (error) { | 191 | } catch (error) { |
| 191 | console.error(`Failed to get Ooba model info: ${error}`); | 192 | console.error(`Failed to get Ooba model info: ${error}`); |
| @@ -726,13 +726,12 @@ router.post('/create', urlencodedParser, async function (request, response) { | |||
| 726 | const char = JSON.stringify(charaFormatData(request.body, request.user.directories)); | 726 | const char = JSON.stringify(charaFormatData(request.body, request.user.directories)); |
| 727 | const internalName = getPngName(request.body.ch_name, request.user.directories); | 727 | const internalName = getPngName(request.body.ch_name, request.user.directories); |
| 728 | const avatarName = `${internalName}.png`; | 728 | const avatarName = `${internalName}.png`; |
| 729 | const defaultAvatar = './public/img/ai4.png'; | ||
| 730 | const chatsPath = path.join(request.user.directories.chats, internalName); | 729 | const chatsPath = path.join(request.user.directories.chats, internalName); |
| 731 | 730 | ||
| 732 | if (!fs.existsSync(chatsPath)) fs.mkdirSync(chatsPath); | 731 | if (!fs.existsSync(chatsPath)) fs.mkdirSync(chatsPath); |
| 733 | 732 | ||
| 734 | if (!request.file) { | 733 | if (!request.file) { |
| 735 | await writeCharacterData(defaultAvatar, char, internalName, request); | 734 | await writeCharacterData(defaultAvatarPath, char, internalName, request); |
| 736 | return response.send(avatarName); | 735 | return response.send(avatarName); |
| 737 | } else { | 736 | } else { |
| 738 | const crop = tryParse(request.query.crop); | 737 | const crop = tryParse(request.query.crop); |
| @@ -1028,6 +1027,12 @@ router.post('/chats', jsonParser, async function (request, response) { | |||
| 1028 | const stats = fs.statSync(pathToFile); | 1027 | const stats = fs.statSync(pathToFile); |
| 1029 | const fileSizeInKB = `${(stats.size / 1024).toFixed(2)}kb`; | 1028 | const fileSizeInKB = `${(stats.size / 1024).toFixed(2)}kb`; |
| 1030 | 1029 | ||
| 1030 | if (stats.size === 0) { | ||
| 1031 | console.log(`Found an empty chat file: ${pathToFile}`); | ||
| 1032 | res({}); | ||
| 1033 | return; | ||
| 1034 | } | ||
| 1035 | |||
| 1031 | const rl = readline.createInterface({ | 1036 | const rl = readline.createInterface({ |
| 1032 | input: fileStream, | 1037 | input: fileStream, |
| 1033 | crlfDelay: Infinity, | 1038 | crlfDelay: Infinity, |
| @@ -4,6 +4,7 @@ const readline = require('readline'); | |||
| 4 | const express = require('express'); | 4 | const express = require('express'); |
| 5 | const sanitize = require('sanitize-filename'); | 5 | const sanitize = require('sanitize-filename'); |
| 6 | const writeFileAtomicSync = require('write-file-atomic').sync; | 6 | const writeFileAtomicSync = require('write-file-atomic').sync; |
| 7 | const _ = require('lodash'); | ||
| 7 | 8 | ||
| 8 | const { jsonParser, urlencodedParser } = require('../express-common'); | 9 | const { jsonParser, urlencodedParser } = require('../express-common'); |
| 9 | const { getConfigValue, humanizedISO8601DateTime, tryParse, generateTimestamp, removeOldBackups } = require('../util'); | 10 | const { getConfigValue, humanizedISO8601DateTime, tryParse, generateTimestamp, removeOldBackups } = require('../util'); |
| @@ -34,6 +35,27 @@ function backupChat(directory, name, chat) { | |||
| 34 | } | 35 | } |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 38 | const backupFunctions = new Map(); | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Gets a backup function for a user. | ||
| 42 | * @param {string} handle User handle | ||
| 43 | * @returns {function(string, string, string): void} Backup function | ||
| 44 | */ | ||
| 45 | function getBackupFunction(handle) { | ||
| 46 | const throttleInterval = getConfigValue('chatBackupThrottleInterval', 10_000); | ||
| 47 | if (!backupFunctions.has(handle)) { | ||
| 48 | backupFunctions.set(handle, _.throttle(backupChat, throttleInterval, { leading: true, trailing: true })); | ||
| 49 | } | ||
| 50 | return backupFunctions.get(handle); | ||
| 51 | } | ||
| 52 | |||
| 53 | process.on('exit', () => { | ||
| 54 | for (const func of backupFunctions.values()) { | ||
| 55 | func.flush(); | ||
| 56 | } | ||
| 57 | }); | ||
| 58 | |||
| 37 | /** | 59 | /** |
| 38 | * Imports a chat from Ooba's format. | 60 | * Imports a chat from Ooba's format. |
| 39 | * @param {string} userName User name | 61 | * @param {string} userName User name |
| @@ -70,8 +92,7 @@ function importOobaChat(userName, characterName, jsonData) { | |||
| 70 | } | 92 | } |
| 71 | } | 93 | } |
| 72 | 94 | ||
| 73 | const chatContent = chat.map(obj => JSON.stringify(obj)).join('\n'); | 95 | return chat.map(obj => JSON.stringify(obj)).join('\n'); |
| 74 | return chatContent; | ||
| 75 | } | 96 | } |
| 76 | 97 | ||
| 77 | /** | 98 | /** |
| @@ -99,8 +120,7 @@ function importAgnaiChat(userName, characterName, jsonData) { | |||
| 99 | }); | 120 | }); |
| 100 | } | 121 | } |
| 101 | 122 | ||
| 102 | const chatContent = chat.map(obj => JSON.stringify(obj)).join('\n'); | 123 | return chat.map(obj => JSON.stringify(obj)).join('\n'); |
| 103 | return chatContent; | ||
| 104 | } | 124 | } |
| 105 | 125 | ||
| 106 | /** | 126 | /** |
| @@ -137,6 +157,37 @@ function importCAIChat(userName, characterName, jsonData) { | |||
| 137 | return newChats; | 157 | return newChats; |
| 138 | } | 158 | } |
| 139 | 159 | ||
| 160 | /** | ||
| 161 | * Flattens `msg` and `swipes` data from Chub Chat format. | ||
| 162 | * Only changes enough to make it compatible with the standard chat serialization format. | ||
| 163 | * @param {string} userName User name | ||
| 164 | * @param {string} characterName Character name | ||
| 165 | * @param {string[]} lines serialised JSONL data | ||
| 166 | * @returns {string} Converted data | ||
| 167 | */ | ||
| 168 | function flattenChubChat(userName, characterName, lines) { | ||
| 169 | function flattenSwipe(swipe) { | ||
| 170 | return swipe.message ? swipe.message : swipe; | ||
| 171 | } | ||
| 172 | |||
| 173 | function convert(line) { | ||
| 174 | const lineData = tryParse(line); | ||
| 175 | if (!lineData) return line; | ||
| 176 | |||
| 177 | if (lineData.mes && lineData.mes.message) { | ||
| 178 | lineData.mes = lineData?.mes.message; | ||
| 179 | } | ||
| 180 | |||
| 181 | if (lineData?.swipes && Array.isArray(lineData.swipes)) { | ||
| 182 | lineData.swipes = lineData.swipes.map(swipe => flattenSwipe(swipe)); | ||
| 183 | } | ||
| 184 | |||
| 185 | return JSON.stringify(lineData); | ||
| 186 | } | ||
| 187 | |||
| 188 | return (lines ?? []).map(convert).join('\n'); | ||
| 189 | } | ||
| 190 | |||
| 140 | const router = express.Router(); | 191 | const router = express.Router(); |
| 141 | 192 | ||
| 142 | router.post('/save', jsonParser, function (request, response) { | 193 | router.post('/save', jsonParser, function (request, response) { |
| @@ -144,10 +195,10 @@ router.post('/save', jsonParser, function (request, response) { | |||
| 144 | const directoryName = String(request.body.avatar_url).replace('.png', ''); | 195 | const directoryName = String(request.body.avatar_url).replace('.png', ''); |
| 145 | const chatData = request.body.chat; | 196 | const chatData = request.body.chat; |
| 146 | const jsonlData = chatData.map(JSON.stringify).join('\n'); | 197 | const jsonlData = chatData.map(JSON.stringify).join('\n'); |
| 147 | const fileName = `${sanitize(String(request.body.file_name))}.jsonl`; | 198 | const fileName = `${String(request.body.file_name)}.jsonl`; |
| 148 | const filePath = path.join(request.user.directories.chats, directoryName, fileName); | 199 | const filePath = path.join(request.user.directories.chats, directoryName, sanitize(fileName)); |
| 149 | writeFileAtomicSync(filePath, jsonlData, 'utf8'); | 200 | writeFileAtomicSync(filePath, jsonlData, 'utf8'); |
| 150 | backupChat(request.user.directories.backups, directoryName, jsonlData); | 201 | getBackupFunction(request.user.profile.handle)(request.user.directories.backups, directoryName, jsonlData); |
| 151 | return response.send({ result: 'ok' }); | 202 | return response.send({ result: 'ok' }); |
| 152 | } catch (error) { | 203 | } catch (error) { |
| 153 | response.send(error); | 204 | response.send(error); |
| @@ -171,14 +222,15 @@ router.post('/get', jsonParser, function (request, response) { | |||
| 171 | return response.send({}); | 222 | return response.send({}); |
| 172 | } | 223 | } |
| 173 | 224 | ||
| 174 | const fileName = path.join(directoryPath, `${sanitize(String(request.body.file_name))}.jsonl`); | 225 | const fileName = `${String(request.body.file_name)}.jsonl`; |
| 175 | const chatFileExists = fs.existsSync(fileName); | 226 | const filePath = path.join(directoryPath, sanitize(fileName)); |
| 227 | const chatFileExists = fs.existsSync(filePath); | ||
| 176 | 228 | ||
| 177 | if (!chatFileExists) { | 229 | if (!chatFileExists) { |
| 178 | return response.send({}); | 230 | return response.send({}); |
| 179 | } | 231 | } |
| 180 | 232 | ||
| 181 | const data = fs.readFileSync(fileName, 'utf8'); | 233 | const data = fs.readFileSync(filePath, 'utf8'); |
| 182 | const lines = data.split('\n'); | 234 | const lines = data.split('\n'); |
| 183 | 235 | ||
| 184 | // Iterate through the array of strings and parse each line as JSON | 236 | // Iterate through the array of strings and parse each line as JSON |
| @@ -199,8 +251,9 @@ router.post('/rename', jsonParser, async function (request, response) { | |||
| 199 | const pathToFolder = request.body.is_group | 251 | const pathToFolder = request.body.is_group |
| 200 | ? request.user.directories.groupChats | 252 | ? request.user.directories.groupChats |
| 201 | : path.join(request.user.directories.chats, String(request.body.avatar_url).replace('.png', '')); | 253 | : path.join(request.user.directories.chats, String(request.body.avatar_url).replace('.png', '')); |
| 202 | const pathToOriginalFile = path.join(pathToFolder, request.body.original_file); | 254 | const pathToOriginalFile = path.join(pathToFolder, sanitize(request.body.original_file)); |
| 203 | const pathToRenamedFile = path.join(pathToFolder, request.body.renamed_file); | 255 | const pathToRenamedFile = path.join(pathToFolder, sanitize(request.body.renamed_file)); |
| 256 | const sanitizedFileName = path.parse(pathToRenamedFile).name; | ||
| 204 | console.log('Old chat name', pathToOriginalFile); | 257 | console.log('Old chat name', pathToOriginalFile); |
| 205 | console.log('New chat name', pathToRenamedFile); | 258 | console.log('New chat name', pathToRenamedFile); |
| 206 | 259 | ||
| @@ -212,32 +265,22 @@ router.post('/rename', jsonParser, async function (request, response) { | |||
| 212 | fs.copyFileSync(pathToOriginalFile, pathToRenamedFile); | 265 | fs.copyFileSync(pathToOriginalFile, pathToRenamedFile); |
| 213 | fs.rmSync(pathToOriginalFile); | 266 | fs.rmSync(pathToOriginalFile); |
| 214 | console.log('Successfully renamed.'); | 267 | console.log('Successfully renamed.'); |
| 215 | return response.send({ ok: true }); | 268 | return response.send({ ok: true, sanitizedFileName }); |
| 216 | }); | 269 | }); |
| 217 | 270 | ||
| 218 | router.post('/delete', jsonParser, function (request, response) { | 271 | router.post('/delete', jsonParser, function (request, response) { |
| 219 | if (!request.body) { | ||
| 220 | console.log('no request body seen'); | ||
| 221 | return response.sendStatus(400); | ||
| 222 | } | ||
| 223 | |||
| 224 | if (request.body.chatfile !== sanitize(request.body.chatfile)) { | ||
| 225 | console.error('Malicious chat name prevented'); | ||
| 226 | return response.sendStatus(403); | ||
| 227 | } | ||
| 228 | |||
| 229 | const dirName = String(request.body.avatar_url).replace('.png', ''); | 272 | const dirName = String(request.body.avatar_url).replace('.png', ''); |
| 230 | const fileName = path.join(request.user.directories.chats, dirName, sanitize(String(request.body.chatfile))); | 273 | const fileName = String(request.body.chatfile); |
| 231 | const chatFileExists = fs.existsSync(fileName); | 274 | const filePath = path.join(request.user.directories.chats, dirName, sanitize(fileName)); |
| 275 | const chatFileExists = fs.existsSync(filePath); | ||
| 232 | 276 | ||
| 233 | if (!chatFileExists) { | 277 | if (!chatFileExists) { |
| 234 | console.log(`Chat file not found '${fileName}'`); | 278 | console.log(`Chat file not found '${filePath}'`); |
| 235 | return response.sendStatus(400); | 279 | return response.sendStatus(400); |
| 236 | } else { | ||
| 237 | fs.rmSync(fileName); | ||
| 238 | console.log('Deleted chat file: ' + fileName); | ||
| 239 | } | 280 | } |
| 240 | 281 | ||
| 282 | fs.rmSync(filePath); | ||
| 283 | console.log('Deleted chat file: ' + filePath); | ||
| 241 | return response.send('ok'); | 284 | return response.send('ok'); |
| 242 | }); | 285 | }); |
| 243 | 286 | ||
| @@ -259,7 +302,7 @@ router.post('/export', jsonParser, async function (request, response) { | |||
| 259 | } | 302 | } |
| 260 | try { | 303 | try { |
| 261 | // Short path for JSONL files | 304 | // Short path for JSONL files |
| 262 | if (request.body.format == 'jsonl') { | 305 | if (request.body.format === 'jsonl') { |
| 263 | try { | 306 | try { |
| 264 | const rawFile = fs.readFileSync(filename, 'utf8'); | 307 | const rawFile = fs.readFileSync(filename, 'utf8'); |
| 265 | const successMessage = { | 308 | const successMessage = { |
| @@ -269,8 +312,7 @@ router.post('/export', jsonParser, async function (request, response) { | |||
| 269 | 312 | ||
| 270 | console.log(`Chat exported as ${exportfilename}`); | 313 | console.log(`Chat exported as ${exportfilename}`); |
| 271 | return response.status(200).json(successMessage); | 314 | return response.status(200).json(successMessage); |
| 272 | } | 315 | } catch (err) { |
| 273 | catch (err) { | ||
| 274 | console.error(err); | 316 | console.error(err); |
| 275 | const errorMessage = { | 317 | const errorMessage = { |
| 276 | message: `Could not read JSONL file to export. Source chat file: ${filename}.`, | 318 | message: `Could not read JSONL file to export. Source chat file: ${filename}.`, |
| @@ -305,8 +347,7 @@ router.post('/export', jsonParser, async function (request, response) { | |||
| 305 | console.log(`Chat exported as ${exportfilename}`); | 347 | console.log(`Chat exported as ${exportfilename}`); |
| 306 | return response.status(200).json(successMessage); | 348 | return response.status(200).json(successMessage); |
| 307 | }); | 349 | }); |
| 308 | } | 350 | } catch (err) { |
| 309 | catch (err) { | ||
| 310 | console.log('chat export failed.'); | 351 | console.log('chat export failed.'); |
| 311 | console.log(err); | 352 | console.log(err); |
| 312 | return response.sendStatus(400); | 353 | return response.sendStatus(400); |
| @@ -382,20 +423,36 @@ router.post('/import', urlencodedParser, function (request, response) { | |||
| 382 | } | 423 | } |
| 383 | 424 | ||
| 384 | if (format === 'jsonl') { | 425 | if (format === 'jsonl') { |
| 385 | const line = data.split('\n')[0]; | 426 | let lines = data.split('\n'); |
| 427 | const header = lines[0]; | ||
| 386 | 428 | ||
| 387 | const jsonData = JSON.parse(line); | 429 | const jsonData = JSON.parse(header); |
| 388 | 430 | ||
| 389 | if (jsonData.user_name !== undefined || jsonData.name !== undefined) { | 431 | if (!(jsonData.user_name !== undefined || jsonData.name !== undefined)) { |
| 390 | const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`; | ||
| 391 | const filePath = path.join(request.user.directories.chats, avatarUrl, fileName); | ||
| 392 | fs.copyFileSync(pathToUpload, filePath); | ||
| 393 | fs.unlinkSync(pathToUpload); | ||
| 394 | response.send({ res: true }); | ||
| 395 | } else { | ||
| 396 | console.log('Incorrect chat format .jsonl'); | 432 | console.log('Incorrect chat format .jsonl'); |
| 397 | return response.send({ error: true }); | 433 | return response.send({ error: true }); |
| 398 | } | 434 | } |
| 435 | |||
| 436 | // Do a tiny bit of work to import Chub Chat data | ||
| 437 | // Processing the entire file is so fast that it's not worth checking if it's a Chub chat first | ||
| 438 | let flattenedChat = data; | ||
| 439 | try { | ||
| 440 | // flattening is unlikely to break, but it's not worth failing to | ||
| 441 | // import normal chats in an attempt to import a Chub chat | ||
| 442 | flattenedChat = flattenChubChat(userName, characterName, lines); | ||
| 443 | } catch (error) { | ||
| 444 | console.warn('Failed to flatten Chub Chat data: ', error); | ||
| 445 | } | ||
| 446 | |||
| 447 | const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`; | ||
| 448 | const filePath = path.join(request.user.directories.chats, avatarUrl, fileName); | ||
| 449 | if (flattenedChat !== data) { | ||
| 450 | writeFileAtomicSync(filePath, flattenedChat, 'utf8'); | ||
| 451 | } else { | ||
| 452 | fs.copyFileSync(pathToUpload, filePath); | ||
| 453 | } | ||
| 454 | fs.unlinkSync(pathToUpload); | ||
| 455 | response.send({ res: true }); | ||
| 399 | } | 456 | } |
| 400 | } catch (error) { | 457 | } catch (error) { |
| 401 | console.error(error); | 458 | console.error(error); |
| @@ -454,7 +511,7 @@ router.post('/group/save', jsonParser, (request, response) => { | |||
| 454 | let chat_data = request.body.chat; | 511 | let chat_data = request.body.chat; |
| 455 | let jsonlData = chat_data.map(JSON.stringify).join('\n'); | 512 | let jsonlData = chat_data.map(JSON.stringify).join('\n'); |
| 456 | writeFileAtomicSync(pathToFile, jsonlData, 'utf8'); | 513 | writeFileAtomicSync(pathToFile, jsonlData, 'utf8'); |
| 457 | backupChat(request.user.directories.backups, String(id), jsonlData); | 514 | getBackupFunction(request.user.profile.handle)(request.user.directories.backups, String(id), jsonlData); |
| 458 | return response.send({ ok: true }); | 515 | return response.send({ ok: true }); |
| 459 | }); | 516 | }); |
| 460 | 517 | ||
| @@ -43,6 +43,7 @@ const CONTENT_TYPES = { | |||
| 43 | CONTEXT: 'context', | 43 | CONTEXT: 'context', |
| 44 | MOVING_UI: 'moving_ui', | 44 | MOVING_UI: 'moving_ui', |
| 45 | QUICK_REPLIES: 'quick_replies', | 45 | QUICK_REPLIES: 'quick_replies', |
| 46 | SYSPROMPT: 'sysprompt', | ||
| 46 | }; | 47 | }; |
| 47 | 48 | ||
| 48 | /** | 49 | /** |
| @@ -56,7 +57,7 @@ function getDefaultPresets(directories) { | |||
| 56 | const presets = []; | 57 | const presets = []; |
| 57 | 58 | ||
| 58 | for (const contentItem of contentIndex) { | 59 | for (const contentItem of contentIndex) { |
| 59 | if (contentItem.type.endsWith('_preset') || contentItem.type === 'instruct' || contentItem.type === 'context') { | 60 | if (contentItem.type.endsWith('_preset') || contentItem.type === 'instruct' || contentItem.type === 'context' || contentItem.type === 'sysprompt') { |
| 60 | contentItem.name = path.parse(contentItem.filename).name; | 61 | contentItem.name = path.parse(contentItem.filename).name; |
| 61 | contentItem.folder = getTargetByType(contentItem.type, directories); | 62 | contentItem.folder = getTargetByType(contentItem.type, directories); |
| 62 | presets.push(contentItem); | 63 | presets.push(contentItem); |
| @@ -218,6 +219,41 @@ function getContentIndex() { | |||
| 218 | } | 219 | } |
| 219 | 220 | ||
| 220 | /** | 221 | /** |
| 222 | * Gets content by type and format. | ||
| 223 | * @param {string} type Type of content | ||
| 224 | * @param {'json'|'string'|'raw'} format Format of content | ||
| 225 | * @returns {string[]|Buffer[]} Array of content | ||
| 226 | */ | ||
| 227 | function getContentOfType(type, format) { | ||
| 228 | const contentIndex = getContentIndex(); | ||
| 229 | const indexItems = contentIndex.filter((item) => item.type === type && item.folder); | ||
| 230 | const files = []; | ||
| 231 | for (const item of indexItems) { | ||
| 232 | if (!item.folder) { | ||
| 233 | continue; | ||
| 234 | } | ||
| 235 | try { | ||
| 236 | const filePath = path.join(item.folder, item.filename); | ||
| 237 | const fileContent = fs.readFileSync(filePath); | ||
| 238 | switch (format) { | ||
| 239 | case 'json': | ||
| 240 | files.push(JSON.parse(fileContent.toString())); | ||
| 241 | break; | ||
| 242 | case 'string': | ||
| 243 | files.push(fileContent.toString()); | ||
| 244 | break; | ||
| 245 | case 'raw': | ||
| 246 | files.push(fileContent); | ||
| 247 | break; | ||
| 248 | } | ||
| 249 | } catch { | ||
| 250 | // Ignore errors | ||
| 251 | } | ||
| 252 | } | ||
| 253 | return files; | ||
| 254 | } | ||
| 255 | |||
| 256 | /** | ||
| 221 | * Gets the target directory for the specified asset type. | 257 | * Gets the target directory for the specified asset type. |
| 222 | * @param {ContentType} type Asset type | 258 | * @param {ContentType} type Asset type |
| 223 | * @param {import('../users').UserDirectoryList} directories User directories | 259 | * @param {import('../users').UserDirectoryList} directories User directories |
| @@ -257,6 +293,8 @@ function getTargetByType(type, directories) { | |||
| 257 | return directories.movingUI; | 293 | return directories.movingUI; |
| 258 | case CONTENT_TYPES.QUICK_REPLIES: | 294 | case CONTENT_TYPES.QUICK_REPLIES: |
| 259 | return directories.quickreplies; | 295 | return directories.quickreplies; |
| 296 | case CONTENT_TYPES.SYSPROMPT: | ||
| 297 | return directories.sysprompt; | ||
| 260 | default: | 298 | default: |
| 261 | return null; | 299 | return null; |
| 262 | } | 300 | } |
| @@ -721,5 +759,6 @@ module.exports = { | |||
| 721 | checkForNewContent, | 759 | checkForNewContent, |
| 722 | getDefaultPresets, | 760 | getDefaultPresets, |
| 723 | getDefaultPresetFile, | 761 | getDefaultPresetFile, |
| 762 | getContentOfType, | ||
| 724 | router, | 763 | router, |
| 725 | }; | 764 | }; |
| @@ -6,6 +6,7 @@ const { readSecret, SECRET_KEYS } = require('./secrets'); | |||
| 6 | const { jsonParser } = require('../express-common'); | 6 | const { jsonParser } = require('../express-common'); |
| 7 | 7 | ||
| 8 | const ANONYMOUS_KEY = '0000000000'; | 8 | const ANONYMOUS_KEY = '0000000000'; |
| 9 | const HORDE_TEXT_MODEL_METADATA_URL = 'https://raw.githubusercontent.com/db0/AI-Horde-text-model-reference/main/db.json'; | ||
| 9 | const cache = new Cache(60 * 1000); | 10 | const cache = new Cache(60 * 1000); |
| 10 | const router = express.Router(); | 11 | const router = express.Router(); |
| 11 | 12 | ||
| @@ -23,10 +24,9 @@ async function getClientAgent() { | |||
| 23 | * @returns {Promise<AIHorde>} AIHorde client | 24 | * @returns {Promise<AIHorde>} AIHorde client |
| 24 | */ | 25 | */ |
| 25 | async function getHordeClient() { | 26 | async function getHordeClient() { |
| 26 | const ai_horde = new AIHorde({ | 27 | return new AIHorde({ |
| 27 | client_agent: await getClientAgent(), | 28 | client_agent: await getClientAgent(), |
| 28 | }); | 29 | }); |
| 29 | return ai_horde; | ||
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | /** | 32 | /** |
| @@ -79,10 +79,24 @@ router.post('/text-workers', jsonParser, async (request, response) => { | |||
| 79 | } | 79 | } |
| 80 | }); | 80 | }); |
| 81 | 81 | ||
| 82 | async function getHordeTextModelMetadata() { | ||
| 83 | const response = await fetch(HORDE_TEXT_MODEL_METADATA_URL); | ||
| 84 | return await response.json(); | ||
| 85 | } | ||
| 86 | |||
| 87 | async function mergeModelsAndMetadata(models, metadata) { | ||
| 88 | return models.map(model => { | ||
| 89 | const metadataModel = metadata[model.name]; | ||
| 90 | if (!metadataModel) { | ||
| 91 | return { ...model, is_whitelisted: false }; | ||
| 92 | } | ||
| 93 | return { ...model, ...metadataModel, is_whitelisted: true }; | ||
| 94 | }); | ||
| 95 | } | ||
| 96 | |||
| 82 | router.post('/text-models', jsonParser, async (request, response) => { | 97 | router.post('/text-models', jsonParser, async (request, response) => { |
| 83 | try { | 98 | try { |
| 84 | const cachedModels = cache.get('models'); | 99 | const cachedModels = cache.get('models'); |
| 85 | |||
| 86 | if (cachedModels && !request.body.force) { | 100 | if (cachedModels && !request.body.force) { |
| 87 | return response.send(cachedModels); | 101 | return response.send(cachedModels); |
| 88 | } | 102 | } |
| @@ -94,7 +108,17 @@ router.post('/text-models', jsonParser, async (request, response) => { | |||
| 94 | }, | 108 | }, |
| 95 | }); | 109 | }); |
| 96 | 110 | ||
| 97 | const data = await fetchResult.json(); | 111 | let data = await fetchResult.json(); |
| 112 | |||
| 113 | // attempt to fetch and merge models metadata | ||
| 114 | try { | ||
| 115 | const metadata = await getHordeTextModelMetadata(); | ||
| 116 | data = await mergeModelsAndMetadata(data, metadata); | ||
| 117 | } | ||
| 118 | catch (error) { | ||
| 119 | console.error('Failed to fetch metadata:', error); | ||
| 120 | } | ||
| 121 | |||
| 98 | cache.set('models', data); | 122 | cache.set('models', data); |
| 99 | return response.send(data); | 123 | return response.send(data); |
| 100 | } catch (error) { | 124 | } catch (error) { |
| @@ -310,6 +334,7 @@ router.post('/generate-image', jsonParser, async (request, response) => { | |||
| 310 | console.log('Stable Horde request:', request.body); | 334 | console.log('Stable Horde request:', request.body); |
| 311 | 335 | ||
| 312 | const ai_horde = await getHordeClient(); | 336 | const ai_horde = await getHordeClient(); |
| 337 | // noinspection JSCheckFunctionSignatures -- see @ts-ignore - use_gfpgan | ||
| 313 | const generation = await ai_horde.postAsyncImageGenerate( | 338 | const generation = await ai_horde.postAsyncImageGenerate( |
| 314 | { | 339 | { |
| 315 | prompt: `${request.body.prompt} ### ${request.body.negative_prompt}`, | 340 | prompt: `${request.body.prompt} ### ${request.body.negative_prompt}`, |
| @@ -15,6 +15,11 @@ const badWordsList = [ | |||
| 15 | [19438], [43145], [26523], [41471], [2936], [85, 85], [49332], [7286], [1115], [24], | 15 | [19438], [43145], [26523], [41471], [2936], [85, 85], [49332], [7286], [1115], [24], |
| 16 | ]; | 16 | ]; |
| 17 | 17 | ||
| 18 | const eratoBadWordsList = [ | ||
| 19 | [16067], [933, 11144], [25106, 11144], [58, 106901, 16073, 33710, 25, 109933], | ||
| 20 | [933, 58, 11144], [128030], [58, 30591, 33503, 17663, 100204, 25, 11144], | ||
| 21 | ]; | ||
| 22 | |||
| 18 | const hypeBotBadWordsList = [ | 23 | const hypeBotBadWordsList = [ |
| 19 | [58], [60], [90], [92], [685], [1391], [1782], [2361], [3693], [4083], [4357], [4895], | 24 | [58], [60], [90], [92], [685], [1391], [1782], [2361], [3693], [4083], [4357], [4895], |
| 20 | [5512], [5974], [7131], [8183], [8351], [8762], [8964], [8973], [9063], [11208], | 25 | [5512], [5974], [7131], [8183], [8351], [8762], [8964], [8973], [9063], [11208], |
| @@ -42,12 +47,24 @@ const repPenaltyAllowList = [ | |||
| 42 | 803, 1040, 49209, 4, 5, 6, 7, 8, 9, 10, 11, 12], | 47 | 803, 1040, 49209, 4, 5, 6, 7, 8, 9, 10, 11, 12], |
| 43 | ]; | 48 | ]; |
| 44 | 49 | ||
| 50 | const eratoRepPenWhitelist = [ | ||
| 51 | 6, 1, 11, 13, 25, 198, 12, 9, 8, 279, 264, 459, 323, 477, 539, 912, 374, 574, 1051, 1550, 1587, 4536, 5828, 15058, | ||
| 52 | 3287, 3250, 1461, 1077, 813, 11074, 872, 1202, 1436, 7846, 1288, 13434, 1053, 8434, 617, 9167, 1047, 19117, 706, | ||
| 53 | 12775, 649, 4250, 527, 7784, 690, 2834, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 1210, 1359, 608, 220, 596, 956, | ||
| 54 | 3077, 44886, 4265, 3358, 2351, 2846, 311, 389, 315, 304, 520, 505, 430 | ||
| 55 | ]; | ||
| 56 | |||
| 45 | // Ban the dinkus and asterism | 57 | // Ban the dinkus and asterism |
| 46 | const logitBiasExp = [ | 58 | const logitBiasExp = [ |
| 47 | { 'sequence': [23], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false }, | 59 | { 'sequence': [23], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false }, |
| 48 | { 'sequence': [21], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false }, | 60 | { 'sequence': [21], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false }, |
| 49 | ]; | 61 | ]; |
| 50 | 62 | ||
| 63 | const eratoLogitBiasExp = [ | ||
| 64 | { 'sequence': [12488], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false }, | ||
| 65 | { 'sequence': [128041], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false }, | ||
| 66 | ]; | ||
| 67 | |||
| 51 | function getBadWordsList(model) { | 68 | function getBadWordsList(model) { |
| 52 | let list = []; | 69 | let list = []; |
| 53 | 70 | ||
| @@ -59,10 +76,40 @@ function getBadWordsList(model) { | |||
| 59 | list = badWordsList; | 76 | list = badWordsList; |
| 60 | } | 77 | } |
| 61 | 78 | ||
| 79 | if (model.includes('erato')) { | ||
| 80 | list = eratoBadWordsList; | ||
| 81 | } | ||
| 82 | |||
| 62 | // Clone the list so we don't modify the original | 83 | // Clone the list so we don't modify the original |
| 63 | return list.slice(); | 84 | return list.slice(); |
| 64 | } | 85 | } |
| 65 | 86 | ||
| 87 | function getLogitBiasList(model) { | ||
| 88 | let list = []; | ||
| 89 | |||
| 90 | if (model.includes('erato')) { | ||
| 91 | list = eratoLogitBiasExp; | ||
| 92 | } | ||
| 93 | |||
| 94 | if (model.includes('clio') || model.includes('kayra')) { | ||
| 95 | list = logitBiasExp; | ||
| 96 | } | ||
| 97 | |||
| 98 | return list.slice(); | ||
| 99 | } | ||
| 100 | |||
| 101 | function getRepPenaltyWhitelist(model) { | ||
| 102 | if (model.includes('clio') || model.includes('kayra')) { | ||
| 103 | return repPenaltyAllowList.flat(); | ||
| 104 | } | ||
| 105 | |||
| 106 | if (model.includes('erato')) { | ||
| 107 | return eratoRepPenWhitelist.flat(); | ||
| 108 | } | ||
| 109 | |||
| 110 | return null; | ||
| 111 | } | ||
| 112 | |||
| 66 | const router = express.Router(); | 113 | const router = express.Router(); |
| 67 | 114 | ||
| 68 | router.post('/status', jsonParser, async function (req, res) { | 115 | router.post('/status', jsonParser, async function (req, res) { |
| @@ -116,11 +163,10 @@ router.post('/generate', jsonParser, async function (req, res) { | |||
| 116 | controller.abort(); | 163 | controller.abort(); |
| 117 | }); | 164 | }); |
| 118 | 165 | ||
| 119 | const isNewModel = (req.body.model.includes('clio') || req.body.model.includes('kayra')); | 166 | // Add customized bad words for Clio, Kayra, and Erato |
| 120 | const badWordsList = getBadWordsList(req.body.model); | 167 | const badWordsList = getBadWordsList(req.body.model); |
| 121 | 168 | ||
| 122 | // Add customized bad words for Clio and Kayra | 169 | if (Array.isArray(badWordsList) && Array.isArray(req.body.bad_words_ids)) { |
| 123 | if (isNewModel && Array.isArray(req.body.bad_words_ids)) { | ||
| 124 | for (const badWord of req.body.bad_words_ids) { | 170 | for (const badWord of req.body.bad_words_ids) { |
| 125 | if (Array.isArray(badWord) && badWord.every(x => Number.isInteger(x))) { | 171 | if (Array.isArray(badWord) && badWord.every(x => Number.isInteger(x))) { |
| 126 | badWordsList.push(badWord); | 172 | badWordsList.push(badWord); |
| @@ -136,12 +182,14 @@ router.post('/generate', jsonParser, async function (req, res) { | |||
| 136 | } | 182 | } |
| 137 | 183 | ||
| 138 | // Add default biases for dinkus and asterism | 184 | // Add default biases for dinkus and asterism |
| 139 | const logit_bias_exp = isNewModel ? logitBiasExp.slice() : []; | 185 | const logitBiasList = getLogitBiasList(req.body.model); |
| 140 | 186 | ||
| 141 | if (Array.isArray(logit_bias_exp) && Array.isArray(req.body.logit_bias_exp)) { | 187 | if (Array.isArray(logitBiasList) && Array.isArray(req.body.logit_bias_exp)) { |
| 142 | logit_bias_exp.push(...req.body.logit_bias_exp); | 188 | logitBiasList.push(...req.body.logit_bias_exp); |
| 143 | } | 189 | } |
| 144 | 190 | ||
| 191 | const repPenWhitelist = getRepPenaltyWhitelist(req.body.model); | ||
| 192 | |||
| 145 | const data = { | 193 | const data = { |
| 146 | 'input': req.body.input, | 194 | 'input': req.body.input, |
| 147 | 'model': req.body.model, | 195 | 'model': req.body.model, |
| @@ -156,31 +204,38 @@ router.post('/generate', jsonParser, async function (req, res) { | |||
| 156 | 'repetition_penalty_slope': req.body.repetition_penalty_slope, | 204 | 'repetition_penalty_slope': req.body.repetition_penalty_slope, |
| 157 | 'repetition_penalty_frequency': req.body.repetition_penalty_frequency, | 205 | 'repetition_penalty_frequency': req.body.repetition_penalty_frequency, |
| 158 | 'repetition_penalty_presence': req.body.repetition_penalty_presence, | 206 | 'repetition_penalty_presence': req.body.repetition_penalty_presence, |
| 159 | 'repetition_penalty_whitelist': isNewModel ? repPenaltyAllowList.flat() : null, | 207 | 'repetition_penalty_whitelist': repPenWhitelist, |
| 160 | 'top_a': req.body.top_a, | 208 | 'top_a': req.body.top_a, |
| 161 | 'top_p': req.body.top_p, | 209 | 'top_p': req.body.top_p, |
| 162 | 'top_k': req.body.top_k, | 210 | 'top_k': req.body.top_k, |
| 163 | 'typical_p': req.body.typical_p, | 211 | 'typical_p': req.body.typical_p, |
| 164 | 'mirostat_lr': req.body.mirostat_lr, | 212 | 'mirostat_lr': req.body.mirostat_lr, |
| 165 | 'mirostat_tau': req.body.mirostat_tau, | 213 | 'mirostat_tau': req.body.mirostat_tau, |
| 166 | 'cfg_scale': req.body.cfg_scale, | ||
| 167 | 'cfg_uc': req.body.cfg_uc, | ||
| 168 | 'phrase_rep_pen': req.body.phrase_rep_pen, | 214 | 'phrase_rep_pen': req.body.phrase_rep_pen, |
| 169 | 'stop_sequences': req.body.stop_sequences, | 215 | 'stop_sequences': req.body.stop_sequences, |
| 170 | 'bad_words_ids': badWordsList.length ? badWordsList : null, | 216 | 'bad_words_ids': badWordsList.length ? badWordsList : null, |
| 171 | 'logit_bias_exp': logit_bias_exp, | 217 | 'logit_bias_exp': logitBiasList, |
| 172 | 'generate_until_sentence': req.body.generate_until_sentence, | 218 | 'generate_until_sentence': req.body.generate_until_sentence, |
| 173 | 'use_cache': req.body.use_cache, | 219 | 'use_cache': req.body.use_cache, |
| 174 | 'return_full_text': req.body.return_full_text, | 220 | 'return_full_text': req.body.return_full_text, |
| 175 | 'prefix': req.body.prefix, | 221 | 'prefix': req.body.prefix, |
| 176 | 'order': req.body.order, | 222 | 'order': req.body.order, |
| 177 | 'num_logprobs': req.body.num_logprobs, | 223 | 'num_logprobs': req.body.num_logprobs, |
| 224 | 'min_p': req.body.min_p, | ||
| 225 | 'math1_temp': req.body.math1_temp, | ||
| 226 | 'math1_quad': req.body.math1_quad, | ||
| 227 | 'math1_quad_entropy_scale': req.body.math1_quad_entropy_scale, | ||
| 178 | }, | 228 | }, |
| 179 | }; | 229 | }; |
| 180 | 230 | ||
| 181 | // Tells the model to stop generation at '>' | 231 | // Tells the model to stop generation at '>' |
| 182 | if ('theme_textadventure' === req.body.prefix && isNewModel) { | 232 | if ('theme_textadventure' === req.body.prefix) { |
| 183 | data.parameters.eos_token_id = 49405; | 233 | if (req.body.model.includes('clio') || req.body.model.includes('kayra')) { |
| 234 | data.parameters.eos_token_id = 49405; | ||
| 235 | } | ||
| 236 | if (req.body.model.includes('erato')) { | ||
| 237 | data.parameters.eos_token_id = 29; | ||
| 238 | } | ||
| 184 | } | 239 | } |
| 185 | 240 | ||
| 186 | console.log(util.inspect(data, { depth: 4 })); | 241 | console.log(util.inspect(data, { depth: 4 })); |
| @@ -192,7 +247,7 @@ router.post('/generate', jsonParser, async function (req, res) { | |||
| 192 | }; | 247 | }; |
| 193 | 248 | ||
| 194 | try { | 249 | try { |
| 195 | const baseURL = req.body.model.includes('kayra') ? TEXT_NOVELAI : API_NOVELAI; | 250 | const baseURL = (req.body.model.includes('kayra') || req.body.model.includes('erato')) ? TEXT_NOVELAI : API_NOVELAI; |
| 196 | const url = req.body.streaming ? `${baseURL}/ai/generate-stream` : `${baseURL}/ai/generate`; | 251 | const url = req.body.streaming ? `${baseURL}/ai/generate-stream` : `${baseURL}/ai/generate`; |
| 197 | const response = await fetch(url, { method: 'POST', timeout: 0, ...args }); | 252 | const response = await fetch(url, { method: 'POST', timeout: 0, ...args }); |
| 198 | 253 | ||
| @@ -51,6 +51,10 @@ router.post('/caption-image', jsonParser, async (request, response) => { | |||
| 51 | key = readSecret(request.user.directories, SECRET_KEYS.ZEROONEAI); | 51 | key = readSecret(request.user.directories, SECRET_KEYS.ZEROONEAI); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | if (request.body.api === 'mistral') { | ||
| 55 | key = readSecret(request.user.directories, SECRET_KEYS.MISTRALAI); | ||
| 56 | } | ||
| 57 | |||
| 54 | if (!key && !request.body.reverse_proxy && ['custom', 'ooba', 'koboldcpp', 'vllm'].includes(request.body.api) === false) { | 58 | if (!key && !request.body.reverse_proxy && ['custom', 'ooba', 'koboldcpp', 'vllm'].includes(request.body.api) === false) { |
| 55 | console.log('No key found for API', request.body.api); | 59 | console.log('No key found for API', request.body.api); |
| 56 | return response.sendStatus(400); | 60 | return response.sendStatus(400); |
| @@ -107,6 +111,10 @@ router.post('/caption-image', jsonParser, async (request, response) => { | |||
| 107 | apiUrl = 'https://api.01.ai/v1/chat/completions'; | 111 | apiUrl = 'https://api.01.ai/v1/chat/completions'; |
| 108 | } | 112 | } |
| 109 | 113 | ||
| 114 | if (request.body.api === 'mistral') { | ||
| 115 | apiUrl = 'https://api.mistral.ai/v1/chat/completions'; | ||
| 116 | } | ||
| 117 | |||
| 110 | if (request.body.api === 'ooba') { | 118 | if (request.body.api === 'ooba') { |
| 111 | apiUrl = `${trimV1(request.body.server_url)}/v1/chat/completions`; | 119 | apiUrl = `${trimV1(request.body.server_url)}/v1/chat/completions`; |
| 112 | const imgMessage = body.messages.pop(); | 120 | const imgMessage = body.messages.pop(); |
| @@ -0,0 +1,32 @@ | |||
| 1 | const express = require('express'); | ||
| 2 | const { jsonParser } = require('../express-common'); | ||
| 3 | |||
| 4 | const router = express.Router(); | ||
| 5 | const API_OPENROUTER = 'https://openrouter.ai/api/v1'; | ||
| 6 | |||
| 7 | router.post('/models/multimodal', jsonParser, async (_req, res) => { | ||
| 8 | try { | ||
| 9 | // The endpoint is available without authentication | ||
| 10 | const response = await fetch(`${API_OPENROUTER}/models`, { | ||
| 11 | method: 'GET', | ||
| 12 | headers: { | ||
| 13 | 'Accept': 'application/json', | ||
| 14 | }, | ||
| 15 | }); | ||
| 16 | |||
| 17 | if (!response.ok) { | ||
| 18 | return res.json([]); | ||
| 19 | } | ||
| 20 | |||
| 21 | const data = await response.json(); | ||
| 22 | const models = data?.data || []; | ||
| 23 | const multimodalModels = models.filter(m => m?.architecture?.modality === 'text+image->text').map(m => m.id); | ||
| 24 | |||
| 25 | return res.json(multimodalModels); | ||
| 26 | } catch (error) { | ||
| 27 | console.error(error); | ||
| 28 | return res.sendStatus(500); | ||
| 29 | } | ||
| 30 | }); | ||
| 31 | |||
| 32 | module.exports = { router }; | ||
| @@ -27,6 +27,8 @@ function getPresetSettingsByAPI(apiId, directories) { | |||
| 27 | return { folder: directories.instruct, extension: '.json' }; | 27 | return { folder: directories.instruct, extension: '.json' }; |
| 28 | case 'context': | 28 | case 'context': |
| 29 | return { folder: directories.context, extension: '.json' }; | 29 | return { folder: directories.context, extension: '.json' }; |
| 30 | case 'sysprompt': | ||
| 31 | return { folder: directories.sysprompt, extension: '.json' }; | ||
| 30 | default: | 32 | default: |
| 31 | return { folder: null, extension: null }; | 33 | return { folder: null, extension: null }; |
| 32 | } | 34 | } |
| @@ -251,6 +251,7 @@ router.post('/get', jsonParser, (request, response) => { | |||
| 251 | 251 | ||
| 252 | const instruct = readAndParseFromDirectory(request.user.directories.instruct); | 252 | const instruct = readAndParseFromDirectory(request.user.directories.instruct); |
| 253 | const context = readAndParseFromDirectory(request.user.directories.context); | 253 | const context = readAndParseFromDirectory(request.user.directories.context); |
| 254 | const sysprompt = readAndParseFromDirectory(request.user.directories.sysprompt); | ||
| 254 | 255 | ||
| 255 | response.send({ | 256 | response.send({ |
| 256 | settings, | 257 | settings, |
| @@ -268,6 +269,7 @@ router.post('/get', jsonParser, (request, response) => { | |||
| 268 | quickReplyPresets, | 269 | quickReplyPresets, |
| 269 | instruct, | 270 | instruct, |
| 270 | context, | 271 | context, |
| 272 | sysprompt, | ||
| 271 | enable_extensions: ENABLE_EXTENSIONS, | 273 | enable_extensions: ENABLE_EXTENSIONS, |
| 272 | enable_extensions_auto_update: ENABLE_EXTENSIONS_AUTO_UPDATE, | 274 | enable_extensions_auto_update: ENABLE_EXTENSIONS_AUTO_UPDATE, |
| 273 | enable_accounts: ENABLE_ACCOUNTS, | 275 | enable_accounts: ENABLE_ACCOUNTS, |
| @@ -221,6 +221,7 @@ const claude_tokenizer = new WebTokenizer('src/tokenizers/claude.json'); | |||
| 221 | const llama3_tokenizer = new WebTokenizer('src/tokenizers/llama3.json'); | 221 | const llama3_tokenizer = new WebTokenizer('src/tokenizers/llama3.json'); |
| 222 | const commandTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/command-r.json', 'src/tokenizers/llama3.json'); | 222 | const commandTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/command-r.json', 'src/tokenizers/llama3.json'); |
| 223 | const qwen2Tokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/qwen2.json', 'src/tokenizers/llama3.json'); | 223 | const qwen2Tokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/qwen2.json', 'src/tokenizers/llama3.json'); |
| 224 | const nemoTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/nemo.json', 'src/tokenizers/llama3.json'); | ||
| 224 | 225 | ||
| 225 | const sentencepieceTokenizers = [ | 226 | const sentencepieceTokenizers = [ |
| 226 | 'llama', | 227 | 'llama', |
| @@ -418,6 +419,10 @@ function getTokenizerModel(requestModel) { | |||
| 418 | return 'command-r'; | 419 | return 'command-r'; |
| 419 | } | 420 | } |
| 420 | 421 | ||
| 422 | if (requestModel.includes('nemo')) { | ||
| 423 | return 'nemo'; | ||
| 424 | } | ||
| 425 | |||
| 421 | // default | 426 | // default |
| 422 | return 'gpt-3.5-turbo'; | 427 | return 'gpt-3.5-turbo'; |
| 423 | } | 428 | } |
| @@ -645,6 +650,7 @@ router.post('/claude/encode', jsonParser, createWebTokenizerEncodingHandler(clau | |||
| 645 | router.post('/llama3/encode', jsonParser, createWebTokenizerEncodingHandler(llama3_tokenizer)); | 650 | router.post('/llama3/encode', jsonParser, createWebTokenizerEncodingHandler(llama3_tokenizer)); |
| 646 | router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer)); | 651 | router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer)); |
| 647 | router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer)); | 652 | router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer)); |
| 653 | router.post('/nemo/encode', jsonParser, createWebTokenizerEncodingHandler(nemoTokenizer)); | ||
| 648 | router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama)); | 654 | router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama)); |
| 649 | router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd)); | 655 | router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd)); |
| 650 | router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2)); | 656 | router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2)); |
| @@ -657,6 +663,7 @@ router.post('/claude/decode', jsonParser, createWebTokenizerDecodingHandler(clau | |||
| 657 | router.post('/llama3/decode', jsonParser, createWebTokenizerDecodingHandler(llama3_tokenizer)); | 663 | router.post('/llama3/decode', jsonParser, createWebTokenizerDecodingHandler(llama3_tokenizer)); |
| 658 | router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer)); | 664 | router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer)); |
| 659 | router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer)); | 665 | router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer)); |
| 666 | router.post('/nemo/decode', jsonParser, createWebTokenizerDecodingHandler(nemoTokenizer)); | ||
| 660 | 667 | ||
| 661 | router.post('/openai/encode', jsonParser, async function (req, res) { | 668 | router.post('/openai/encode', jsonParser, async function (req, res) { |
| 662 | try { | 669 | try { |
| @@ -707,6 +714,11 @@ router.post('/openai/encode', jsonParser, async function (req, res) { | |||
| 707 | return handler(req, res); | 714 | return handler(req, res); |
| 708 | } | 715 | } |
| 709 | 716 | ||
| 717 | if (queryModel.includes('nemo')) { | ||
| 718 | const handler = createWebTokenizerEncodingHandler(nemoTokenizer); | ||
| 719 | return handler(req, res); | ||
| 720 | } | ||
| 721 | |||
| 710 | const model = getTokenizerModel(queryModel); | 722 | const model = getTokenizerModel(queryModel); |
| 711 | const handler = createTiktokenEncodingHandler(model); | 723 | const handler = createTiktokenEncodingHandler(model); |
| 712 | return handler(req, res); | 724 | return handler(req, res); |
| @@ -765,6 +777,11 @@ router.post('/openai/decode', jsonParser, async function (req, res) { | |||
| 765 | return handler(req, res); | 777 | return handler(req, res); |
| 766 | } | 778 | } |
| 767 | 779 | ||
| 780 | if (queryModel.includes('nemo')) { | ||
| 781 | const handler = createWebTokenizerDecodingHandler(nemoTokenizer); | ||
| 782 | return handler(req, res); | ||
| 783 | } | ||
| 784 | |||
| 768 | const model = getTokenizerModel(queryModel); | 785 | const model = getTokenizerModel(queryModel); |
| 769 | const handler = createTiktokenDecodingHandler(model); | 786 | const handler = createTiktokenDecodingHandler(model); |
| 770 | return handler(req, res); | 787 | return handler(req, res); |
| @@ -835,6 +852,13 @@ router.post('/openai/count', jsonParser, async function (req, res) { | |||
| 835 | return res.send({ 'token_count': num_tokens }); | 852 | return res.send({ 'token_count': num_tokens }); |
| 836 | } | 853 | } |
| 837 | 854 | ||
| 855 | if (model === 'nemo') { | ||
| 856 | const instance = await nemoTokenizer.get(); | ||
| 857 | if (!instance) throw new Error('Failed to load the Nemo tokenizer'); | ||
| 858 | num_tokens = countWebTokenizerTokens(instance, req.body); | ||
| 859 | return res.send({ 'token_count': num_tokens }); | ||
| 860 | } | ||
| 861 | |||
| 838 | const tokensPerName = queryModel.includes('gpt-3.5-turbo-0301') ? -1 : 1; | 862 | const tokensPerName = queryModel.includes('gpt-3.5-turbo-0301') ? -1 : 1; |
| 839 | const tokensPerMessage = queryModel.includes('gpt-3.5-turbo-0301') ? 4 : 3; | 863 | const tokensPerMessage = queryModel.includes('gpt-3.5-turbo-0301') ? 4 : 3; |
| 840 | const tokensPadding = 3; | 864 | const tokensPadding = 3; |
| @@ -4,6 +4,7 @@ const fs = require('fs'); | |||
| 4 | const express = require('express'); | 4 | const express = require('express'); |
| 5 | const sanitize = require('sanitize-filename'); | 5 | const sanitize = require('sanitize-filename'); |
| 6 | const { jsonParser } = require('../express-common'); | 6 | const { jsonParser } = require('../express-common'); |
| 7 | const { getConfigValue, color } = require('../util'); | ||
| 7 | 8 | ||
| 8 | // Don't forget to add new sources to the SOURCES array | 9 | // Don't forget to add new sources to the SOURCES array |
| 9 | const SOURCES = [ | 10 | const SOURCES = [ |
| @@ -110,18 +111,94 @@ async function getBatchVector(source, sourceSettings, texts, isQuery, directorie | |||
| 110 | } | 111 | } |
| 111 | 112 | ||
| 112 | /** | 113 | /** |
| 114 | * Extracts settings for the vectorization sources from the HTTP request headers. | ||
| 115 | * @param {string} source - Which source to extract settings for. | ||
| 116 | * @param {object} request - The HTTP request object. | ||
| 117 | * @returns {object} - An object that can be used as `sourceSettings` in functions that take that parameter. | ||
| 118 | */ | ||
| 119 | function getSourceSettings(source, request) { | ||
| 120 | switch (source) { | ||
| 121 | case 'togetherai': | ||
| 122 | return { | ||
| 123 | model: String(request.headers['x-togetherai-model']), | ||
| 124 | }; | ||
| 125 | case 'openai': | ||
| 126 | return { | ||
| 127 | model: String(request.headers['x-openai-model']), | ||
| 128 | }; | ||
| 129 | case 'cohere': | ||
| 130 | return { | ||
| 131 | model: String(request.headers['x-cohere-model']), | ||
| 132 | }; | ||
| 133 | case 'llamacpp': | ||
| 134 | return { | ||
| 135 | apiUrl: String(request.headers['x-llamacpp-url']), | ||
| 136 | }; | ||
| 137 | case 'vllm': | ||
| 138 | return { | ||
| 139 | apiUrl: String(request.headers['x-vllm-url']), | ||
| 140 | model: String(request.headers['x-vllm-model']), | ||
| 141 | }; | ||
| 142 | case 'ollama': | ||
| 143 | return { | ||
| 144 | apiUrl: String(request.headers['x-ollama-url']), | ||
| 145 | model: String(request.headers['x-ollama-model']), | ||
| 146 | keep: Boolean(request.headers['x-ollama-keep']), | ||
| 147 | }; | ||
| 148 | case 'extras': | ||
| 149 | return { | ||
| 150 | extrasUrl: String(request.headers['x-extras-url']), | ||
| 151 | extrasKey: String(request.headers['x-extras-key']), | ||
| 152 | }; | ||
| 153 | case 'local': | ||
| 154 | return { | ||
| 155 | model: getConfigValue('extras.embeddingModel', ''), | ||
| 156 | }; | ||
| 157 | case 'palm': | ||
| 158 | return { | ||
| 159 | // TODO: Add support for multiple models | ||
| 160 | model: 'text-embedding-004', | ||
| 161 | }; | ||
| 162 | default: | ||
| 163 | return {}; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | /** | ||
| 168 | * Gets the model scope for the source. | ||
| 169 | * @param {object} sourceSettings - The settings for the source | ||
| 170 | * @returns {string} The model scope for the source | ||
| 171 | */ | ||
| 172 | function getModelScope(sourceSettings) { | ||
| 173 | const scopesEnabled = getConfigValue('vectors.enableModelScopes', false); | ||
| 174 | const warningShown = global.process.env.VECTORS_MODEL_SCOPE_WARNING_SHOWN === 'true'; | ||
| 175 | |||
| 176 | if (!scopesEnabled && !warningShown) { | ||
| 177 | console.log(); | ||
| 178 | console.warn(color.red('[DEPRECATION NOTICE]'), 'Model scopes for Vectore Storage are disabled, but will soon be required.'); | ||
| 179 | console.log(`To enable model scopes, set the ${color.cyan('vectors.enableModelScopes')} in config.yaml to ${color.green(true)}.`); | ||
| 180 | console.log('This message won\'t be shown again in the current session.'); | ||
| 181 | console.log(); | ||
| 182 | global.process.env.VECTORS_MODEL_SCOPE_WARNING_SHOWN = 'true'; | ||
| 183 | } | ||
| 184 | |||
| 185 | return scopesEnabled ? (sourceSettings?.model || '') : ''; | ||
| 186 | } | ||
| 187 | |||
| 188 | /** | ||
| 113 | * Gets the index for the vector collection | 189 | * Gets the index for the vector collection |
| 114 | * @param {import('../users').UserDirectoryList} directories - User directories | 190 | * @param {import('../users').UserDirectoryList} directories - User directories |
| 115 | * @param {string} collectionId - The collection ID | 191 | * @param {string} collectionId - The collection ID |
| 116 | * @param {string} source - The source of the vector | 192 | * @param {string} source - The source of the vector |
| 117 | * @param {boolean} create - Whether to create the index if it doesn't exist | 193 | * @param {object} sourceSettings - The model for the source |
| 118 | * @returns {Promise<vectra.LocalIndex>} - The index for the collection | 194 | * @returns {Promise<vectra.LocalIndex>} - The index for the collection |
| 119 | */ | 195 | */ |
| 120 | async function getIndex(directories, collectionId, source, create = true) { | 196 | async function getIndex(directories, collectionId, source, sourceSettings) { |
| 121 | const pathToFile = path.join(directories.vectors, sanitize(source), sanitize(collectionId)); | 197 | const model = getModelScope(sourceSettings); |
| 198 | const pathToFile = path.join(directories.vectors, sanitize(source), sanitize(collectionId), sanitize(model)); | ||
| 122 | const store = new vectra.LocalIndex(pathToFile); | 199 | const store = new vectra.LocalIndex(pathToFile); |
| 123 | 200 | ||
| 124 | if (create && !await store.isIndexCreated()) { | 201 | if (!await store.isIndexCreated()) { |
| 125 | await store.createIndex(); | 202 | await store.createIndex(); |
| 126 | } | 203 | } |
| 127 | 204 | ||
| @@ -137,7 +214,7 @@ async function getIndex(directories, collectionId, source, create = true) { | |||
| 137 | * @param {{ hash: number; text: string; index: number; }[]} items - The items to insert | 214 | * @param {{ hash: number; text: string; index: number; }[]} items - The items to insert |
| 138 | */ | 215 | */ |
| 139 | async function insertVectorItems(directories, collectionId, source, sourceSettings, items) { | 216 | async function insertVectorItems(directories, collectionId, source, sourceSettings, items) { |
| 140 | const store = await getIndex(directories, collectionId, source); | 217 | const store = await getIndex(directories, collectionId, source, sourceSettings); |
| 141 | 218 | ||
| 142 | await store.beginUpdate(); | 219 | await store.beginUpdate(); |
| 143 | 220 | ||
| @@ -157,10 +234,11 @@ async function insertVectorItems(directories, collectionId, source, sourceSettin | |||
| 157 | * @param {import('../users').UserDirectoryList} directories - User directories | 234 | * @param {import('../users').UserDirectoryList} directories - User directories |
| 158 | * @param {string} collectionId - The collection ID | 235 | * @param {string} collectionId - The collection ID |
| 159 | * @param {string} source - The source of the vector | 236 | * @param {string} source - The source of the vector |
| 237 | * @param {Object} sourceSettings - Settings for the source, if it needs any | ||
| 160 | * @returns {Promise<number[]>} - The hashes of the items in the collection | 238 | * @returns {Promise<number[]>} - The hashes of the items in the collection |
| 161 | */ | 239 | */ |
| 162 | async function getSavedHashes(directories, collectionId, source) { | 240 | async function getSavedHashes(directories, collectionId, source, sourceSettings) { |
| 163 | const store = await getIndex(directories, collectionId, source); | 241 | const store = await getIndex(directories, collectionId, source, sourceSettings); |
| 164 | 242 | ||
| 165 | const items = await store.listItems(); | 243 | const items = await store.listItems(); |
| 166 | const hashes = items.map(x => Number(x.metadata.hash)); | 244 | const hashes = items.map(x => Number(x.metadata.hash)); |
| @@ -173,10 +251,11 @@ async function getSavedHashes(directories, collectionId, source) { | |||
| 173 | * @param {import('../users').UserDirectoryList} directories - User directories | 251 | * @param {import('../users').UserDirectoryList} directories - User directories |
| 174 | * @param {string} collectionId - The collection ID | 252 | * @param {string} collectionId - The collection ID |
| 175 | * @param {string} source - The source of the vector | 253 | * @param {string} source - The source of the vector |
| 254 | * @param {Object} sourceSettings - Settings for the source, if it needs any | ||
| 176 | * @param {number[]} hashes - The hashes of the items to delete | 255 | * @param {number[]} hashes - The hashes of the items to delete |
| 177 | */ | 256 | */ |
| 178 | async function deleteVectorItems(directories, collectionId, source, hashes) { | 257 | async function deleteVectorItems(directories, collectionId, source, sourceSettings, hashes) { |
| 179 | const store = await getIndex(directories, collectionId, source); | 258 | const store = await getIndex(directories, collectionId, source, sourceSettings); |
| 180 | const items = await store.listItemsByMetadata({ hash: { '$in': hashes } }); | 259 | const items = await store.listItemsByMetadata({ hash: { '$in': hashes } }); |
| 181 | 260 | ||
| 182 | await store.beginUpdate(); | 261 | await store.beginUpdate(); |
| @@ -200,7 +279,7 @@ async function deleteVectorItems(directories, collectionId, source, hashes) { | |||
| 200 | * @returns {Promise<{hashes: number[], metadata: object[]}>} - The metadata of the items that match the search text | 279 | * @returns {Promise<{hashes: number[], metadata: object[]}>} - The metadata of the items that match the search text |
| 201 | */ | 280 | */ |
| 202 | async function queryCollection(directories, collectionId, source, sourceSettings, searchText, topK, threshold) { | 281 | async function queryCollection(directories, collectionId, source, sourceSettings, searchText, topK, threshold) { |
| 203 | const store = await getIndex(directories, collectionId, source); | 282 | const store = await getIndex(directories, collectionId, source, sourceSettings); |
| 204 | const vector = await getVector(source, sourceSettings, searchText, true, directories); | 283 | const vector = await getVector(source, sourceSettings, searchText, true, directories); |
| 205 | 284 | ||
| 206 | const result = await store.queryItems(vector, topK); | 285 | const result = await store.queryItems(vector, topK); |
| @@ -226,7 +305,7 @@ async function multiQueryCollection(directories, collectionIds, source, sourceSe | |||
| 226 | const results = []; | 305 | const results = []; |
| 227 | 306 | ||
| 228 | for (const collectionId of collectionIds) { | 307 | for (const collectionId of collectionIds) { |
| 229 | const store = await getIndex(directories, collectionId, source); | 308 | const store = await getIndex(directories, collectionId, source, sourceSettings); |
| 230 | const result = await store.queryItems(vector, topK); | 309 | const result = await store.queryItems(vector, topK); |
| 231 | results.push(...result.map(result => ({ collectionId, result }))); | 310 | results.push(...result.map(result => ({ collectionId, result }))); |
| 232 | } | 311 | } |
| @@ -255,71 +334,6 @@ async function multiQueryCollection(directories, collectionIds, source, sourceSe | |||
| 255 | } | 334 | } |
| 256 | 335 | ||
| 257 | /** | 336 | /** |
| 258 | * Extracts settings for the vectorization sources from the HTTP request headers. | ||
| 259 | * @param {string} source - Which source to extract settings for. | ||
| 260 | * @param {object} request - The HTTP request object. | ||
| 261 | * @returns {object} - An object that can be used as `sourceSettings` in functions that take that parameter. | ||
| 262 | */ | ||
| 263 | function getSourceSettings(source, request) { | ||
| 264 | if (source === 'togetherai') { | ||
| 265 | const model = String(request.headers['x-togetherai-model']); | ||
| 266 | |||
| 267 | return { | ||
| 268 | model: model, | ||
| 269 | }; | ||
| 270 | } else if (source === 'openai') { | ||
| 271 | const model = String(request.headers['x-openai-model']); | ||
| 272 | |||
| 273 | return { | ||
| 274 | model: model, | ||
| 275 | }; | ||
| 276 | } else if (source === 'cohere') { | ||
| 277 | const model = String(request.headers['x-cohere-model']); | ||
| 278 | |||
| 279 | return { | ||
| 280 | model: model, | ||
| 281 | }; | ||
| 282 | } else if (source === 'llamacpp') { | ||
| 283 | const apiUrl = String(request.headers['x-llamacpp-url']); | ||
| 284 | |||
| 285 | return { | ||
| 286 | apiUrl: apiUrl, | ||
| 287 | }; | ||
| 288 | } else if (source === 'vllm') { | ||
| 289 | const apiUrl = String(request.headers['x-vllm-url']); | ||
| 290 | const model = String(request.headers['x-vllm-model']); | ||
| 291 | |||
| 292 | return { | ||
| 293 | apiUrl: apiUrl, | ||
| 294 | model: model, | ||
| 295 | }; | ||
| 296 | } else if (source === 'ollama') { | ||
| 297 | const apiUrl = String(request.headers['x-ollama-url']); | ||
| 298 | const model = String(request.headers['x-ollama-model']); | ||
| 299 | const keep = Boolean(request.headers['x-ollama-keep']); | ||
| 300 | |||
| 301 | return { | ||
| 302 | apiUrl: apiUrl, | ||
| 303 | model: model, | ||
| 304 | keep: keep, | ||
| 305 | }; | ||
| 306 | } else { | ||
| 307 | // Extras API settings to connect to the Extras embeddings provider | ||
| 308 | let extrasUrl = ''; | ||
| 309 | let extrasKey = ''; | ||
| 310 | if (source === 'extras') { | ||
| 311 | extrasUrl = String(request.headers['x-extras-url']); | ||
| 312 | extrasKey = String(request.headers['x-extras-key']); | ||
| 313 | } | ||
| 314 | |||
| 315 | return { | ||
| 316 | extrasUrl: extrasUrl, | ||
| 317 | extrasKey: extrasKey, | ||
| 318 | }; | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | /** | ||
| 323 | * Performs a request to regenerate the index if it is corrupted. | 337 | * Performs a request to regenerate the index if it is corrupted. |
| 324 | * @param {import('express').Request} req Express request object | 338 | * @param {import('express').Request} req Express request object |
| 325 | * @param {import('express').Response} res Express response object | 339 | * @param {import('express').Response} res Express response object |
| @@ -330,9 +344,10 @@ async function regenerateCorruptedIndexErrorHandler(req, res, error) { | |||
| 330 | if (error instanceof SyntaxError && !req.query.regenerated) { | 344 | if (error instanceof SyntaxError && !req.query.regenerated) { |
| 331 | const collectionId = String(req.body.collectionId); | 345 | const collectionId = String(req.body.collectionId); |
| 332 | const source = String(req.body.source) || 'transformers'; | 346 | const source = String(req.body.source) || 'transformers'; |
| 347 | const sourceSettings = getSourceSettings(source, req); | ||
| 333 | 348 | ||
| 334 | if (collectionId && source) { | 349 | if (collectionId && source) { |
| 335 | const index = await getIndex(req.user.directories, collectionId, source, false); | 350 | const index = await getIndex(req.user.directories, collectionId, source, sourceSettings); |
| 336 | const exists = await index.isIndexCreated(); | 351 | const exists = await index.isIndexCreated(); |
| 337 | 352 | ||
| 338 | if (exists) { | 353 | if (exists) { |
| @@ -350,6 +365,11 @@ async function regenerateCorruptedIndexErrorHandler(req, res, error) { | |||
| 350 | 365 | ||
| 351 | const router = express.Router(); | 366 | const router = express.Router(); |
| 352 | 367 | ||
| 368 | router.get('/scopes-enabled', (_req, res) => { | ||
| 369 | const scopesEnabled = getConfigValue('vectors.enableModelScopes', false); | ||
| 370 | return res.json({ enabled: scopesEnabled }); | ||
| 371 | }); | ||
| 372 | |||
| 353 | router.post('/query', jsonParser, async (req, res) => { | 373 | router.post('/query', jsonParser, async (req, res) => { |
| 354 | try { | 374 | try { |
| 355 | if (!req.body.collectionId || !req.body.searchText) { | 375 | if (!req.body.collectionId || !req.body.searchText) { |
| @@ -416,8 +436,9 @@ router.post('/list', jsonParser, async (req, res) => { | |||
| 416 | 436 | ||
| 417 | const collectionId = String(req.body.collectionId); | 437 | const collectionId = String(req.body.collectionId); |
| 418 | const source = String(req.body.source) || 'transformers'; | 438 | const source = String(req.body.source) || 'transformers'; |
| 439 | const sourceSettings = getSourceSettings(source, req); | ||
| 419 | 440 | ||
| 420 | const hashes = await getSavedHashes(req.user.directories, collectionId, source); | 441 | const hashes = await getSavedHashes(req.user.directories, collectionId, source, sourceSettings); |
| 421 | return res.json(hashes); | 442 | return res.json(hashes); |
| 422 | } catch (error) { | 443 | } catch (error) { |
| 423 | return regenerateCorruptedIndexErrorHandler(req, res, error); | 444 | return regenerateCorruptedIndexErrorHandler(req, res, error); |
| @@ -433,8 +454,9 @@ router.post('/delete', jsonParser, async (req, res) => { | |||
| 433 | const collectionId = String(req.body.collectionId); | 454 | const collectionId = String(req.body.collectionId); |
| 434 | const hashes = req.body.hashes.map(x => Number(x)); | 455 | const hashes = req.body.hashes.map(x => Number(x)); |
| 435 | const source = String(req.body.source) || 'transformers'; | 456 | const source = String(req.body.source) || 'transformers'; |
| 457 | const sourceSettings = getSourceSettings(source, req); | ||
| 436 | 458 | ||
| 437 | await deleteVectorItems(req.user.directories, collectionId, source, hashes); | 459 | await deleteVectorItems(req.user.directories, collectionId, source, sourceSettings, hashes); |
| 438 | return res.sendStatus(200); | 460 | return res.sendStatus(200); |
| 439 | } catch (error) { | 461 | } catch (error) { |
| 440 | return regenerateCorruptedIndexErrorHandler(req, res, error); | 462 | return regenerateCorruptedIndexErrorHandler(req, res, error); |
| @@ -468,17 +490,12 @@ router.post('/purge', jsonParser, async (req, res) => { | |||
| 468 | const collectionId = String(req.body.collectionId); | 490 | const collectionId = String(req.body.collectionId); |
| 469 | 491 | ||
| 470 | for (const source of SOURCES) { | 492 | for (const source of SOURCES) { |
| 471 | const index = await getIndex(req.user.directories, collectionId, source, false); | 493 | const sourcePath = path.join(req.user.directories.vectors, sanitize(source), sanitize(collectionId)); |
| 472 | 494 | if (!fs.existsSync(sourcePath)) { | |
| 473 | const exists = await index.isIndexCreated(); | ||
| 474 | |||
| 475 | if (!exists) { | ||
| 476 | continue; | 495 | continue; |
| 477 | } | 496 | } |
| 478 | 497 | await fs.promises.rm(sourcePath, { recursive: true }); | |
| 479 | const path = index.folderPath; | 498 | console.log(`Deleted vector index at ${sourcePath}`); |
| 480 | await index.deleteIndex(); | ||
| 481 | console.log(`Deleted vector index at ${path}`); | ||
| 482 | } | 499 | } |
| 483 | 500 | ||
| 484 | return res.sendStatus(200); | 501 | return res.sendStatus(200); |
| @@ -267,11 +267,14 @@ function convertGooglePrompt(messages, model, useSysPrompt = false, charName = ' | |||
| 267 | 'gemini-1.5-flash', | 267 | 'gemini-1.5-flash', |
| 268 | 'gemini-1.5-flash-latest', | 268 | 'gemini-1.5-flash-latest', |
| 269 | 'gemini-1.5-flash-001', | 269 | 'gemini-1.5-flash-001', |
| 270 | 'gemini-1.5-flash-002', | ||
| 270 | 'gemini-1.5-flash-exp-0827', | 271 | 'gemini-1.5-flash-exp-0827', |
| 271 | 'gemini-1.5-flash-8b-exp-0827', | 272 | 'gemini-1.5-flash-8b-exp-0827', |
| 273 | 'gemini-1.5-flash-8b-exp-0924', | ||
| 272 | 'gemini-1.5-pro', | 274 | 'gemini-1.5-pro', |
| 273 | 'gemini-1.5-pro-latest', | 275 | 'gemini-1.5-pro-latest', |
| 274 | 'gemini-1.5-pro-001', | 276 | 'gemini-1.5-pro-001', |
| 277 | 'gemini-1.5-pro-002', | ||
| 275 | 'gemini-1.5-pro-exp-0801', | 278 | 'gemini-1.5-pro-exp-0801', |
| 276 | 'gemini-1.5-pro-exp-0827', | 279 | 'gemini-1.5-pro-exp-0827', |
| 277 | 'gemini-1.0-pro-vision-latest', | 280 | 'gemini-1.0-pro-vision-latest', |
| @@ -9,8 +9,10 @@ const storage = require('node-persist'); | |||
| 9 | const express = require('express'); | 9 | const express = require('express'); |
| 10 | const mime = require('mime-types'); | 10 | const mime = require('mime-types'); |
| 11 | const archiver = require('archiver'); | 11 | const archiver = require('archiver'); |
| 12 | const writeFileAtomicSync = require('write-file-atomic').sync; | ||
| 13 | const _ = require('lodash'); | ||
| 12 | 14 | ||
| 13 | const { USER_DIRECTORY_TEMPLATE, DEFAULT_USER, PUBLIC_DIRECTORIES, DEFAULT_AVATAR, SETTINGS_FILE } = require('./constants'); | 15 | const { USER_DIRECTORY_TEMPLATE, DEFAULT_USER, PUBLIC_DIRECTORIES, SETTINGS_FILE } = require('./constants'); |
| 14 | const { getConfigValue, color, delay, setConfigValue, generateTimestamp } = require('./util'); | 16 | const { getConfigValue, color, delay, setConfigValue, generateTimestamp } = require('./util'); |
| 15 | const { readSecret, writeSecret } = require('./endpoints/secrets'); | 17 | const { readSecret, writeSecret } = require('./endpoints/secrets'); |
| 16 | 18 | ||
| @@ -24,6 +26,7 @@ const ANON_CSRF_SECRET = crypto.randomBytes(64).toString('base64'); | |||
| 24 | * @type {Map<string, UserDirectoryList>} | 26 | * @type {Map<string, UserDirectoryList>} |
| 25 | */ | 27 | */ |
| 26 | const DIRECTORIES_CACHE = new Map(); | 28 | const DIRECTORIES_CACHE = new Map(); |
| 29 | const PUBLIC_USER_AVATAR = '/img/default-user.png'; | ||
| 27 | 30 | ||
| 28 | const STORAGE_KEYS = { | 31 | const STORAGE_KEYS = { |
| 29 | csrfSecret: 'csrfSecret', | 32 | csrfSecret: 'csrfSecret', |
| @@ -82,6 +85,7 @@ const STORAGE_KEYS = { | |||
| 82 | * @property {string} files - The directory where the uploaded files are stored | 85 | * @property {string} files - The directory where the uploaded files are stored |
| 83 | * @property {string} vectors - The directory where the vectors are stored | 86 | * @property {string} vectors - The directory where the vectors are stored |
| 84 | * @property {string} backups - The directory where the backups are stored | 87 | * @property {string} backups - The directory where the backups are stored |
| 88 | * @property {string} sysprompt - The directory where the system prompt data is stored | ||
| 85 | */ | 89 | */ |
| 86 | 90 | ||
| 87 | /** | 91 | /** |
| @@ -322,6 +326,60 @@ async function migrateUserData() { | |||
| 322 | console.log(color.green('Migration completed!')); | 326 | console.log(color.green('Migration completed!')); |
| 323 | } | 327 | } |
| 324 | 328 | ||
| 329 | async function migrateSystemPrompts() { | ||
| 330 | /** | ||
| 331 | * Gets the default system prompts. | ||
| 332 | * @returns {Promise<any[]>} - The list of default system prompts | ||
| 333 | */ | ||
| 334 | async function getDefaultSystemPrompts() { | ||
| 335 | try { | ||
| 336 | const { getContentOfType } = await import('./endpoints/content-manager.js'); | ||
| 337 | return getContentOfType('sysprompt', 'json'); | ||
| 338 | } catch { | ||
| 339 | return []; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | const directories = await getUserDirectoriesList(); | ||
| 344 | for (const directory of directories) { | ||
| 345 | try { | ||
| 346 | const migrateMarker = path.join(directory.sysprompt, '.migrated'); | ||
| 347 | if (fs.existsSync(migrateMarker)) { | ||
| 348 | continue; | ||
| 349 | } | ||
| 350 | const defaultPrompts = await getDefaultSystemPrompts(); | ||
| 351 | const instucts = fs.readdirSync(directory.instruct); | ||
| 352 | let migratedPrompts = []; | ||
| 353 | for (const instruct of instucts) { | ||
| 354 | const instructPath = path.join(directory.instruct, instruct); | ||
| 355 | const sysPromptPath = path.join(directory.sysprompt, instruct); | ||
| 356 | if (path.extname(instruct) === '.json' && !fs.existsSync(sysPromptPath)) { | ||
| 357 | const instructData = JSON.parse(fs.readFileSync(instructPath, 'utf8')); | ||
| 358 | if ('system_prompt' in instructData && 'name' in instructData) { | ||
| 359 | const syspromptData = { name: instructData.name, content: instructData.system_prompt }; | ||
| 360 | migratedPrompts.push(syspromptData); | ||
| 361 | delete instructData.system_prompt; | ||
| 362 | writeFileAtomicSync(instructPath, JSON.stringify(instructData, null, 4)); | ||
| 363 | } | ||
| 364 | } | ||
| 365 | } | ||
| 366 | // Only leave unique contents | ||
| 367 | migratedPrompts = _.uniqBy(migratedPrompts, 'content'); | ||
| 368 | // Only leave contents that are not in the default prompts | ||
| 369 | migratedPrompts = migratedPrompts.filter(x => !defaultPrompts.some(y => y.content === x.content)); | ||
| 370 | for (const sysPromptData of migratedPrompts) { | ||
| 371 | sysPromptData.name = `[Migrated] ${sysPromptData.name}`; | ||
| 372 | const syspromptPath = path.join(directory.sysprompt, `${sysPromptData.name}.json`); | ||
| 373 | writeFileAtomicSync(syspromptPath, JSON.stringify(sysPromptData, null, 4)); | ||
| 374 | console.log(`Migrated system prompt ${sysPromptData.name} for ${directory.root.split(path.sep).pop()}`); | ||
| 375 | } | ||
| 376 | writeFileAtomicSync(migrateMarker, ''); | ||
| 377 | } catch { | ||
| 378 | // Ignore errors | ||
| 379 | } | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 325 | /** | 383 | /** |
| 326 | * Converts a user handle to a storage key. | 384 | * Converts a user handle to a storage key. |
| 327 | * @param {string} handle User handle | 385 | * @param {string} handle User handle |
| @@ -478,11 +536,11 @@ async function getUserAvatar(handle) { | |||
| 478 | const settings = fs.existsSync(pathToSettings) ? JSON.parse(fs.readFileSync(pathToSettings, 'utf8')) : {}; | 536 | const settings = fs.existsSync(pathToSettings) ? JSON.parse(fs.readFileSync(pathToSettings, 'utf8')) : {}; |
| 479 | const avatarFile = settings?.power_user?.default_persona || settings?.user_avatar; | 537 | const avatarFile = settings?.power_user?.default_persona || settings?.user_avatar; |
| 480 | if (!avatarFile) { | 538 | if (!avatarFile) { |
| 481 | return DEFAULT_AVATAR; | 539 | return PUBLIC_USER_AVATAR; |
| 482 | } | 540 | } |
| 483 | const avatarPath = path.join(directory.avatars, avatarFile); | 541 | const avatarPath = path.join(directory.avatars, avatarFile); |
| 484 | if (!fs.existsSync(avatarPath)) { | 542 | if (!fs.existsSync(avatarPath)) { |
| 485 | return DEFAULT_AVATAR; | 543 | return PUBLIC_USER_AVATAR; |
| 486 | } | 544 | } |
| 487 | const mimeType = mime.lookup(avatarPath); | 545 | const mimeType = mime.lookup(avatarPath); |
| 488 | const base64Content = fs.readFileSync(avatarPath, 'base64'); | 546 | const base64Content = fs.readFileSync(avatarPath, 'base64'); |
| @@ -490,7 +548,7 @@ async function getUserAvatar(handle) { | |||
| 490 | } | 548 | } |
| 491 | catch { | 549 | catch { |
| 492 | // Ignore errors | 550 | // Ignore errors |
| 493 | return DEFAULT_AVATAR; | 551 | return PUBLIC_USER_AVATAR; |
| 494 | } | 552 | } |
| 495 | } | 553 | } |
| 496 | 554 | ||
| @@ -723,6 +781,7 @@ module.exports = { | |||
| 723 | requireLoginMiddleware, | 781 | requireLoginMiddleware, |
| 724 | requireAdminMiddleware, | 782 | requireAdminMiddleware, |
| 725 | migrateUserData, | 783 | migrateUserData, |
| 784 | migrateSystemPrompts, | ||
| 726 | getPasswordSalt, | 785 | getPasswordSalt, |
| 727 | getPasswordHash, | 786 | getPasswordHash, |
| 728 | getCsrfSecret, | 787 | getCsrfSecret, |
| @@ -26,7 +26,7 @@ fi | |||
| 26 | 26 | ||
| 27 | echo "Installing Node Modules..." | 27 | echo "Installing Node Modules..." |
| 28 | export NODE_ENV=production | 28 | export NODE_ENV=production |
| 29 | npm i --no-audit --no-fund --quiet --omit=dev | 29 | npm i --no-audit --no-fund --loglevel=error --no-progress --omit=dev |
| 30 | 30 | ||
| 31 | echo "Entering SillyTavern..." | 31 | echo "Entering SillyTavern..." |
| 32 | node "server.js" "$@" | 32 | node "server.js" "$@" |