Merge pull request #4189 from SillyTavern/staging Staging
Signed| @@ -320,29 +320,29 @@ Start.bat --port 8000 --listen false | |||
| 320 | 320 | ||
| 321 | ### Unterstützte Argumente | 321 | ### Unterstützte Argumente |
| 322 | 322 | ||
| 323 | | Option | Beschreibung | Typ | | 323 | | Option | Beschreibung | Typ | |
| 324 | |-------------------------|----------------------------------------------------------------------------------------------------|----------| | 324 | |----------------------------------|--------------------------------------------------------------------------------------------------|----------| |
| 325 | | `--version` | Versionsnummer anzeigen | boolean | | 325 | | `--version` | Versionsnummer anzeigen | boolean | |
| 326 | | `--enableIPv6` | Aktiviert IPv6. | boolean | | 326 | | `--enableIPv6` | Aktiviert IPv6. | boolean | |
| 327 | | `--enableIPv4` | Aktiviert IPv4. | boolean | | 327 | | `--enableIPv4` | Aktiviert IPv4. | boolean | |
| 328 | | `--port` | Legt den Port fest, unter dem SillyTavern ausgeführt wird. Wenn nicht angegeben, wird auf YAML-Konfiguration „Port“ zurückgegriffen. | number | | 328 | | `--port` | Legt den Port fest, unter dem SillyTavern ausgeführt wird. | number | |
| 329 | | „--dnsPreferIPv6“ | Bevorzugt IPv6 für DNS. Wenn nicht angegeben, wird auf YAML-Konfiguration „preferIPv6“ zurückgegriffen. | boolean | | 329 | | `--dnsPreferIPv6` | Bevorzugt IPv6 für DNS. Wenn nicht angegeben. | boolean | |
| 330 | | „--autorun“ | Startet SillyTavern automatisch im Browser. Wenn nicht angegeben, wird auf YAML-Konfiguration „autorun“ zurückgegriffen.| boolean | | 330 | | `--browserLaunchEnabled` | Startet SillyTavern automatisch im Browser. | boolean | |
| 331 | | „--autorunHostname“ | Der Autorun-Hostname, am besten auf „auto“ belassen. | string | | 331 | | `--browserLaunchHostname` | Der Autorun-Hostname, am besten auf „auto" belassen. | string | |
| 332 | | „--autorunPortOverride“ | Überschreibt den Port für Autorun. | string | | 332 | | `--browserLaunchPort` | Überschreibt den Port für Autorun. | string | |
| 333 | | „--listen“ | SillyTavern lauscht auf allen Netzwerkschnittstellen. Wenn nicht angegeben, wird auf YAML-Konfiguration „listen“ zurückgegriffen.| boolean | | 333 | | `--browserLaunchAvoidLocalhost` | Vermeidet die Verwendung von „localhost" für Autorun im Auto-Modus. | boolean | |
| 334 | | „--corsProxy“ | Aktiviert CORS-Proxy. Wenn nicht angegeben, wird auf YAML-Konfiguration „enableCorsProxy“ zurückgegriffen. | boolean | | 334 | | `--listen` | SillyTavern lauscht auf allen Netzwerkschnittstellen. | boolean | |
| 335 | | `--disableCsrf` | Deaktiviert CSRF-Schutz | boolean | | 335 | | `--corsProxy` | Aktiviert CORS-Proxy. Wenn nicht angegeben. | boolean | |
| 336 | | `--ssl` | Aktiviert SSL | boolean | | 336 | | `--disableCsrf` | Deaktiviert CSRF-Schutz | boolean | |
| 337 | | `--certPath` | Pfad zu Ihrer Zertifikatsdatei. | string | | 337 | | `--ssl` | Aktiviert SSL | boolean | |
| 338 | | `--keyPath` | Pfad zu Ihrer privaten Schlüsseldatei. | string | | 338 | | `--certPath` | Pfad zu Ihrer Zertifikatsdatei. | string | |
| 339 | | `--whitelist` | Aktiviert den Whitelist-Modus | boolean | | 339 | | `--keyPath` | Pfad zu Ihrer privaten Schlüsseldatei. | string | |
| 340 | | `--dataRoot` | Stammverzeichnis für Datenspeicherung | string | | 340 | | `--whitelist` | Aktiviert den Whitelist-Modus | boolean | |
| 341 | | `--avoidLocalhost` | Vermeidet die Verwendung von „localhost“ für Autorun im Auto-Modus. | boolean | | 341 | | `--dataRoot` | Stammverzeichnis für Datenspeicherung | string | |
| 342 | | `--basicAuthMode` | Aktiviert die grundlegende Authentifizierung | boolean | | 342 | | `--basicAuthMode` | Aktiviert die grundlegende Authentifizierung | boolean | |
| 343 | | `--requestProxyEnabled` | Aktiviert die Verwendung eines Proxys für ausgehende Anfragen | boolean | | 343 | | `--requestProxyEnabled` | Aktiviert die Verwendung eines Proxys für ausgehende Anfragen | boolean | |
| 344 | | `--requestProxyUrl` | Proxy-URL anfordern (HTTP- oder SOCKS-Protokolle) | string | | 344 | | `--requestProxyUrl` | Proxy-URL anfordern (HTTP- oder SOCKS-Protokolle) | string | |
| 345 | | `--requestProxyBypass` | Proxy-Bypass-Liste anfordern (durch Leerzeichen getrennte Liste von Hosts) | Array | | 345 | | `--requestProxyBypass` | Proxy-Bypass-Liste anfordern (durch Leerzeichen getrennte Liste von Hosts) | Array | |
| 346 | 346 | ||
| 347 | ## Remoteverbindungen | 347 | ## Remoteverbindungen |
| 348 | 348 | ||
| @@ -334,29 +334,29 @@ Start.bat --port 8000 --listen false | |||
| 334 | 334 | ||
| 335 | ### 지원되는 인수 | 335 | ### 지원되는 인수 |
| 336 | 336 | ||
| 337 | | 옵션 | 설명 | 타입 | | 337 | | 옵션 | 설명 | 타입 | |
| 338 | |-------------------------|------------------------------------------------------------------------------------------------------|----------| | 338 | |-----------------------------------|--------------------------------------------------------------------------------------|----------| |
| 339 | | `--version` | 버전 표시 | boolean | | 339 | | `--version` | 버전 표시 | boolean | |
| 340 | | `--enableIPv6` | IPv6 활성화 | boolean | | 340 | | `--enableIPv6` | IPv6 활성화 | boolean | |
| 341 | | `--enableIPv4` | IPv4 활성화 | boolean | | 341 | | `--enableIPv4` | IPv4 활성화 | boolean | |
| 342 | | `--port` | SillyTavern이 실행될 포트를 설정합니다. 설정되지 않은 경우 yaml config 'port'를 불러옵니다. | number | | 342 | | `--port` | SillyTavern이 실행될 포트를 설정합니다. | number | |
| 343 | | `--dnsPreferIPv6` | DNS에 IPv6를 우선으로 할당합니다. 설정되지 않은 경우 yaml config를 불러옵니다. | boolean | | 343 | | `--dnsPreferIPv6` | DNS에 IPv6를 우선으로 할당합니다. | boolean | |
| 344 | | `--autorun` | 브라우저에서 SillyTavern을 자동으로 실행합니다. 설정되지 않은 경우 yaml config 'autorun'를 불러옵니다. | boolean | | 344 | | `--browserLaunchEnabled` | 브라우저에서 SillyTavern을 자동으로 실행합니다. | boolean | |
| 345 | | `--autorunHostname` | 자동 실행 호스트 이름, 'auto'가 최적의 설정일 것입니다. | string | | 345 | | `--browserLaunchHostname` | 자동 실행 호스트 이름, 'auto'가 최적의 설정일 것입니다. | string | |
| 346 | | `--autorunPortOverride` | 자동 실행 포트 덮어쓰기 | string | | 346 | | `--browserLaunchPort` | 자동 실행 포트 덮어쓰기 | string | |
| 347 | | `--listen` | SillyTavern이 모든 네트워크 인터페이스에서 수신 대기합니다. 설정되지 않은 경우 yaml 구성 'listen'을 불러옵니다. | boolean | | 347 | | `--browserLaunchAvoidLocalhost` | 자동 모드에서 자동 실행 시 'localhost' 사용 방지 | boolean | |
| 348 | | `--corsProxy` | CORS 프록시 활성화. 설정되지 않은 경우 yaml 구성 'enableCorsProxy'을 불러옵니다. | boolean | | 348 | | `--listen` | SillyTavern이 모든 네트워크 인터페이스에서 수신 대기합니다. | boolean | |
| 349 | | `--disableCsrf` | CSRF 보호 비활성화 | boolean | | 349 | | `--corsProxy` | CORS 프록시 활성화. | boolean | |
| 350 | | `--ssl` | SSL 활성화 | boolean | | 350 | | `--disableCsrf` | CSRF 보호 비활성화 | boolean | |
| 351 | | `--certPath` | 인증서 파일 경로 | string | | 351 | | `--ssl` | SSL 활성화 | boolean | |
| 352 | | `--keyPath` | 프라이빗 키 파일 경로 | string | | 352 | | `--certPath` | 인증서 파일 경로 | string | |
| 353 | | `--whitelist` | 화이트리스트 모드 활성화 | boolean | | 353 | | `--keyPath` | 프라이빗 키 파일 경로 | string | |
| 354 | | `--dataRoot` | 데이터 스토리지의 루트 디렉토리 | string | | 354 | | `--whitelist` | 화이트리스트 모드 활성화 | boolean | |
| 355 | | `--avoidLocalhost` | 자동 모드에서 자동 실행 시 'localhost' 사용 방지 | boolean | | 355 | | `--dataRoot` | 데이터 스토리지의 루트 디렉토리 | string | |
| 356 | | `--basicAuthMode` | 기본 인증 활성화 | boolean | | 356 | | `--basicAuthMode` | 기본 인증 활성화 | boolean | |
| 357 | | `--requestProxyEnabled` | 외부 리퀘스트 프록시 활성화 | boolean | | 357 | | `--requestProxyEnabled` | 외부 리퀘스트 프록시 활성화 | boolean | |
| 358 | | `--requestProxyUrl` | 프록시 URL 리퀘스트 (HTTP 혹은 SOCKS 프로토콜) | string | | 358 | | `--requestProxyUrl` | 프록시 URL 리퀘스트 (HTTP 혹은 SOCKS 프로토콜) | string | |
| 359 | | `--requestProxyBypass` | 프록시 바이패스 리스트 리퀘스트 (공백으로 구분된 호스트 목록) | array | | 359 | | `--requestProxyBypass` | 프록시 바이패스 리스트 리퀘스트 (공백으로 구분된 호스트 목록) | array | |
| 360 | 360 | ||
| 361 | ## 원격 연결 | 361 | ## 원격 연결 |
| 362 | 362 | ||
| @@ -283,29 +283,29 @@ Start.bat --port 8000 --listen false | |||
| 283 | 283 | ||
| 284 | ### Поддерживаемые аргументы | 284 | ### Поддерживаемые аргументы |
| 285 | 285 | ||
| 286 | | Аргумент | Описание | Тип | | 286 | | Аргумент | Описание | Тип | |
| 287 | |-------------------------|----------------------------------------------------------------------------------------------------------------|----------| | 287 | |------------------------------|-----------------------------------------------------------------------------------------------------------|---------| |
| 288 | | `--version` | Показывает номер версии. | boolean | | 288 | | `--version` | Показывает номер версии. | boolean | |
| 289 | | `--enableIPv6` | Включает IPv6. | boolean | | 289 | | `--enableIPv6` | Включает IPv6. | boolean | |
| 290 | | `--enableIPv4` | Включает IPv4. | boolean | | 290 | | `--enableIPv4` | Включает IPv4. | boolean | |
| 291 | | `--port` | Устанавливает порт, котрый будет использовать SillyTavern. Если не указан, то используется yaml-конфиг 'port'. | number | | 291 | | `--port` | Устанавливает порт, который будет использовать SillyTavern. | number | |
| 292 | | `--dnsPreferIPv6` | Отдает предпочтение IPv6 для dns. Если не указан, то используется yaml-конфиг 'preferIPv6'. | boolean | | 292 | | `--dnsPreferIPv6` | Отдает предпочтение IPv6 для dns. | boolean | |
| 293 | | `--autorun` | Автоматический запуск SillyTavern в браузере. Если не указан, то используется yaml-конфиг 'autorun'. | boolean | | 293 | | `--browserLaunchEnabled` | Автоматический запуск SillyTavern в браузере. | boolean | |
| 294 | | `--autorunHostname` | Имя хоста автозапуска, лучше оставить на 'auto'. | string | | 294 | | `--browserLaunchHostname` | Имя хоста автозапуска, лучше оставить на 'auto'. | string | |
| 295 | | `--autorunPortOverride` | Переопределяет порт для автозапуска. | string | | 295 | | `--browserLaunchPort` | Переопределяет порт для автозапуска. | string | |
| 296 | | `--listen` | SillyTavern будет прослушивать все сетевые интерфейсы. Если не указан, то используется yaml-конфиг 'listen'. | boolean | | 296 | | `--browserLaunchAvoidLocalhost`| Избегает использования 'localhost' для автозапуска в режиме 'auto'. | boolean | |
| 297 | | `--corsProxy` | Включает CORS-прокси. Если не указан, то используется yaml-конфиг 'enableCorsProxy'. | boolean | | 297 | | `--listen` | SillyTavern будет прослушивать все сетевые интерфейсы. | boolean | |
| 298 | | `--disableCsrf` | Отключает защиту от CSRF. | boolean | | 298 | | `--corsProxy` | Включает CORS-прокси. | boolean | |
| 299 | | `--ssl` | Включает SSL. | boolean | | 299 | | `--disableCsrf` | Отключает защиту от CSRF. | boolean | |
| 300 | | `--certPath` | Путь к файлу c сертификатом. | string | | 300 | | `--ssl` | Включает SSL. | boolean | |
| 301 | | `--keyPath` | Путь к файлу с закрытым ключом. | string | | 301 | | `--certPath` | Путь к файлу c сертификатом. | string | |
| 302 | | `--whitelist` | Включает режим белого списка. | boolean | | 302 | | `--keyPath` | Путь к файлу с закрытым ключом. | string | |
| 303 | | `--dataRoot` | Корневой каталог для хранения данных. | string | | 303 | | `--whitelist` | Включает режим белого списка. | boolean | |
| 304 | | `--avoidLocalhost` | Избегает использования 'localhost' для автозапуска в режиме 'auto'. | boolean | | 304 | | `--dataRoot` | Корневой каталог для хранения данных. | string | |
| 305 | | `--basicAuthMode` | Включает простую аутентификацию. | boolean | | 305 | | `--basicAuthMode` | Включает простую аутентификацию. | boolean | |
| 306 | | `--requestProxyEnabled` | Разрешает использование прокси для исходящих запросов. | boolean | | 306 | | `--requestProxyEnabled` | Разрешает использование прокси для исходящих запросов. | boolean | |
| 307 | | `--requestProxyUrl` | URL-адрес прокси (протоколы HTTP или SOCKS). | string | | 307 | | `--requestProxyUrl` | URL-адрес прокси (протоколы HTTP или SOCKS). | string | |
| 308 | | `--requestProxyBypass` | Bypass список прокси (список хостов, разделенных пробелами). | array | | 308 | | `--requestProxyBypass` | Bypass список прокси (список хостов, разделенных пробелами). | array | |
| 309 | 309 | ||
| 310 | ## Удалённое подключение | 310 | ## Удалённое подключение |
| 311 | 311 | ||
| @@ -1,6 +1,8 @@ | |||
| 1 | > [!IMPORTANT] | 1 | > [!IMPORTANT] |
| 2 | > 这里的信息可能已经过时或不完整,仅供您参考。请使用英文版本获取最新信息。 | 2 | > 这里的信息可能已经过时或不完整,仅供您参考。请使用英文版本获取最新信息。 |
| 3 | 3 | ||
| 4 | <a name="readme-top"></a> | ||
| 5 | |||
| 4 | ![][cover] | 6 | ![][cover] |
| 5 | 7 | ||
| 6 | <div align="center"> | 8 | <div align="center"> |
| @@ -8,7 +10,7 @@ | |||
| 8 | [English](readme.md) | [German](readme-de_de.md) | 中文 | [繁體中文](readme-zh_tw.md) | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) | [한국어](readme-ko_kr.md) | 10 | [English](readme.md) | [German](readme-de_de.md) | 中文 | [繁體中文](readme-zh_tw.md) | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) | [한국어](readme-ko_kr.md) |
| 9 | 11 | ||
| 10 | [](https://github.com/SillyTavern/SillyTavern/stargazers) | 12 | [](https://github.com/SillyTavern/SillyTavern/stargazers) |
| 11 | [](https://github.com/SillyTavern/SillyTavern/network) | 13 | [](https://github.com/SillyTavern/SillyTavern/forks) |
| 12 | [](https://github.com/SillyTavern/SillyTavern/issues) | 14 | [](https://github.com/SillyTavern/SillyTavern/issues) |
| 13 | [](https://github.com/SillyTavern/SillyTavern/pulls) | 15 | [](https://github.com/SillyTavern/SillyTavern/pulls) |
| 14 | 16 | ||
| @@ -16,307 +18,379 @@ | |||
| 16 | 18 | ||
| 17 | --- | 19 | --- |
| 18 | 20 | ||
| 19 | 移动设备界面友好,多种人工智能服务或模型支持(KoboldAI/CPP, Horde, NovelAI, Ooba, OpenAI, OpenRouter, Claude, Scale),类似 Galgame 的 老 婆 模 式,Horde SD,文本系统语音生成,世界信息(Lorebooks),可定制的界面,自动翻译,和比你所需要的更多的 Prompt。附带扩展服务,支持文本绘画生成与语音生成和基于向量数据库 的聊天信息总结。 | 21 | SillyTavern 为众多 LLM API(KoboldAI/CPP、Horde、NovelAI、Ooba、Tabby、OpenAI、OpenRouter、Claude、Mistral 等)提供统一界面,拥有移动设备友好的布局、视觉小说模式、Automatic1111 & ComfyUI API 图像生成集成、TTS、世界书(lorebooks)、可自定义的 UI、自动翻译、超乎您想象的丰富 Prompt 选项,以及通过第三方扩展实现的无限增长潜力。 |
| 20 | 22 | ||
| 21 | 基于 TavernAI 1.2.8 的分叉版本 | 23 | 我们有一个[文档网站](https://docs.sillytavern.app/)来回答您的大部分问题并帮助您入门。 |
| 22 | 24 | ||
| 23 | ### 由 Cohee、RossAscends 和 SillyTavern 社区为您呈现 | 25 | ## SillyTavern 是什么? |
| 24 | 26 | ||
| 25 | 注意:我们创建了一个 [帮助文档](https://docs.sillytavern.app/) 网站来回答各类问题与帮助您开始使用。 | 27 | SillyTavern(简称 ST)是一个本地安装的用户界面,允许您与文本生成 LLM、图像生成引擎和 TTS 语音模型进行交互。 |
| 26 | 28 | ||
| 27 | ### SillyTavern 或 TavernAI 是什么? | 29 | SillyTavern 于 2023 年 2 月作为 TavernAI 1.2.8 的一个分支开始,如今已拥有超过 200 名贡献者和 2 年的独立开发经验,并继续作为资深 AI 爱好者领先的软件。 |
| 28 | 30 | ||
| 29 | SillyTavern 是一个可以安装在电脑(和安卓手机)上的用户界面,让您可以与文本生成的人工智能互动,并与您或社区创建的角色聊天/玩角色扮演游戏。 | 31 | ## 我们的愿景 |
| 30 | 32 | ||
| 31 | SillyTavern 是 TavernAI 1.2.8 的一个分支,正在进行更积极地开发,并添加了许多重要功能。在这一点上,它可以被视为完全独立的程序。 | 33 | 1. 我们的目标是尽可能为用户提供 LLM Prompt 的最大效用和控制权。陡峭的学习曲线是乐趣的一部分! |
| 34 | 2. 我们不提供任何在线或托管服务,也不会以编程方式跟踪任何用户数据。 | ||
| 35 | 3. SillyTavern 是一个由专注的 LLM 爱好者社区为您带来的充满激情的项目,并且将永远是免费和开源的。 | ||
| 32 | 36 | ||
| 33 | ### 分支 | 37 | ## 分支 |
| 34 | 38 | ||
| 35 | SillyTavern 采用双分支进行开发,以确保所有用户都能获得流畅的使用体验。 | 39 | SillyTavern 采用双分支进行开发,以确保所有用户都能获得流畅的使用体验。 |
| 36 | 40 | ||
| 37 | * release -🌟 **推荐给大多数用户。** 这是最稳定、最推荐的分支,只有在重大版本推送时才会更新。适合大多数用户使用。 | 41 | - `release` -🌟 **推荐给大多数用户。** 这是最稳定、最推荐的分支,只有在重大版本推送时才会更新。适合大多数用户使用。通常每月更新一次。 |
| 38 | * staging - ⚠️ **不建议随意使用。** 该分支拥有最新功能,但要谨慎,因为它随时可能崩溃。仅适用于高级用户和爱好者。 | 42 | - `staging` - ⚠️ **不建议随意使用。** 该分支拥有最新功能,但要谨慎,因为它随时可能崩溃。仅适用于高级用户和爱好者。每天更新数次。 |
| 39 | 43 | ||
| 40 | 如果你不熟悉使用 Git 命令,或者不了解什么是分支,别担心!release 分支始终是您的首选。 | 44 | 如果你不熟悉使用 git 命令行,或者不了解什么是分支,别担心!`release` 分支始终是您的首选。 |
| 41 | 45 | ||
| 42 | ### 除了 SillyTavern,我还需要什么? | 46 | ## 除了 SillyTavern,我还需要什么? |
| 43 | 47 | ||
| 44 | SillyTavern 本身并无用处,因为它只是一个用户聊天界面。你必须接入一个能充当角色扮演的人工智能系统。支持的人工智能系统有多种:OpenAPI API (GPT)、KoboldAI(可在本地或 Google Colab 上运行)等。您可以在 [常见问题](https://docs.sillytavern.app/usage/faq/) 中阅读更多相关信息。 | 48 | 由于 SillyTavern 只是一个界面,您需要接入一个 LLM 后端来进行推理。您可以使用 AI Horde 进行开箱即用的聊天。除此之外,我们还支持许多其他本地和基于云的 LLM 后端:OpenAI 兼容 API、KoboldAI、Tabby 等等。您可以在[文档](https://docs.sillytavern.app/usage/api-connections/)中阅读更多关于我们支持的 API 的信息。 |
| 45 | 49 | ||
| 46 | ### 我需要一台性能强大的电脑来运行 SillyTavern 吗? | 50 | ### 我需要一台性能强大的电脑来运行 SillyTavern 吗? |
| 47 | 51 | ||
| 48 | 由于 SillyTavern 只是一个用户聊天界面,它对硬件性能的要求很低,可以在任何电脑上运行。需要强大性能的是人工智能系统。 | 52 | 硬件要求很低:任何可以运行 NodeJS 18 或更高版本的设备都可以运行它。如果您打算在本地计算机上进行 LLM 推理,我们建议使用至少具有 6GB VRAM 的 3000 系列 NVIDIA 显卡。有关更多详细信息,请查看您后端的文档。 |
| 49 | 53 | ||
| 50 | ### 移动设备支持 | 54 | ### 建议的后端(非附属) |
| 51 | 55 | ||
| 52 | > 注意 | 56 | - [AI Horde](https://aihorde.net/) - 使用志愿者托管的模型。无需进一步设置。 |
| 57 | - [KoboldCpp](https://github.com/LostRuins/koboldcpp) - 社区最喜欢的在本地运行 GGUF 模型的工具。 | ||
| 58 | - [tabbyAPI](https://github.com/theroyallab/tabbyAPI) - 一款流行的、轻量级的、本地托管的 exl2 推理 API。 | ||
| 59 | - [OpenRouter](https://openrouter.ai) - 一个适用于许多云提供商(OpenAI、Claude、Meta Llama 等)以及流行社区模型的单一 API。 | ||
| 53 | 60 | ||
| 54 | > **此分叉可使用 Termux 在安卓手机上原生运行。请参考 ArroganceComplex#2659 编写的指南:** | 61 | ## 有问题或建议? |
| 55 | 62 | ||
| 56 | <https://rentry.org/STAI-Termux> | 63 | ### Discord 服务器 |
| 57 | 64 | ||
| 58 | ## 有问题或建议? | 65 | | [![][discord-shield-badge]][discord-link] | [加入我们的 Discord 社区!](https://discord.gg/sillytavern) 获取支持,分享喜爱的角色和 Prompt。 | |
| 66 | | :---------------------------------------- | :---------------------------------------------------------------------------------------------- | | ||
| 59 | 67 | ||
| 60 | ### 我们现在有了 Discord 社区 | 68 | 或者直接与开发人员联系: |
| 61 | 69 | ||
| 62 | 获取支持,或分享喜爱的角色和 Prompt: | 70 | - Discord: cohee, rossascends, wolfsblvt |
| 71 | - 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/) | ||
| 72 | - [提交 GitHub 问题](https://github.com/SillyTavern/SillyTavern/issues) | ||
| 63 | 73 | ||
| 64 | ### [加入 Discord 社区](https://discord.gg/sillytavern) | 74 | ### 我喜欢你的项目!我该如何贡献自己的力量? |
| 65 | 75 | ||
| 66 | *** | 76 | 1. 发送 Pull Request。学习如何贡献:[CONTRIBUTING.md](../CONTRIBUTING.md) |
| 77 | 2. 使用提供的模板发送功能建议和问题报告。 | ||
| 78 | 3. 请先阅读整个 readme 文件并查看文档网站,以避免提交重复的问题。 | ||
| 67 | 79 | ||
| 68 | 直接与开发人员联系: | 80 | ## 屏幕截图 |
| 69 | 81 | ||
| 70 | * Discord: cohee 或 rossascends | 82 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> |
| 71 | * Reddit:/u/RossAscends 或 /u/sillylossy | 83 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> |
| 72 | * [发布 GitHub 问题](https://github.com/SillyTavern/SillyTavern/issues) | ||
| 73 | 84 | ||
| 74 | ## 此版本包括 | 85 | ## 角色卡 |
| 75 | 86 | ||
| 76 | * 经过大量修改的 TavernAI 1.2.8(超过 50% 的代码经过重写或优化) | 87 | SillyTavern 围绕“角色卡”的概念构建。角色卡是设定 LLM 行为的 Prompt 集合,是在 SillyTavern 中进行持久对话所必需的。它们的功能类似于 ChatGPT 的 GPTs 或 Poe 的 bots。角色卡的内容可以是任何东西:一个抽象的场景、一个为特定任务量身定制的助手、一个著名人物或一个虚构角色。 |
| 77 | * 根据自定义规则自动重新生成消息 | ||
| 78 | * 群聊:多机器人房间,供角色与你或彼此交谈 | ||
| 79 | * 聊天书签/分支(复制当前状态下的对话) | ||
| 80 | * 先进的 KoboldAI / TextGen 生成设置,包含大量社区预设 | ||
| 81 | * 支持世界信息(Lorebooks):创建丰富的传说 | ||
| 82 | * 支持 Window AI 浏览器扩展(运行 Claude、GPT 4 等模型):<https://windowai.io/> | ||
| 83 | * [Oobabooga's TextGen WebUI](https://github.com/oobabooga/text-generation-webui) API 连接 | ||
| 84 | * 连接 [AI Horde](https://aihorde.net/) | ||
| 85 | * Prompt 生成格式调整 | ||
| 86 | * Webp 角色卡支持(PNG 仍是内部格式) | ||
| 87 | 88 | ||
| 88 | ## 扩展 | 89 | 要在不选择角色卡的情况下进行快速对话或仅测试 LLM 连接,只需在打开 SillyTavern 后在欢迎屏幕的输入栏中键入您的 Prompt 输入。这将创建一个空的“助手”角色卡,您可以稍后自定义。 |
| 89 | 90 | ||
| 90 | SillyTavern 支持扩展服务。 | 91 | 要大致了解如何定义角色卡,请参阅默认角色(Seraphina)或从“下载扩展和资源”菜单中下载选定的社区制作卡片。 |
| 91 | 92 | ||
| 92 | * 角色情绪识别 | 93 | ## 主要功能 |
| 93 | * 聊天记录自动摘要 | ||
| 94 | * 在聊天窗口发送图片,并由人工智能解释图片内容 | ||
| 95 | * 文本图像生成(5 预设,以及 "自由模式") | ||
| 96 | * 聊天信息的文字转语音(通过 ElevenLabs、Silero 或操作系统的语音生成) | ||
| 97 | 94 | ||
| 98 | 扩展服务的完整功能介绍和使用教程,请参阅 [Docs](https://docs.sillytavern.app/)。 | 95 | - 高级文本生成设置,包含许多社区制作的预设 |
| 96 | - 世界书支持:创建丰富的传说或节省角色卡上的 Token | ||
| 97 | - 群聊:多机器人房间,供角色与您或彼此交谈 | ||
| 98 | - 丰富的 UI 自定义选项:主题颜色、背景图片、自定义 CSS 等 | ||
| 99 | - 用户角色:让 AI 了解一些关于您的信息,以获得更强的沉浸感 | ||
| 100 | - 内置 RAG 支持:将文档添加到您的聊天中供 AI 参考 | ||
| 101 | - 广泛的聊天命令子系统和自己的[脚本引擎](https://docs.sillytavern.app/usage/st-script/) | ||
| 99 | 102 | ||
| 100 | ## 界面/CSS/性能,由 RossAscends 调整并优化 | 103 | ## 扩展 |
| 101 | 104 | ||
| 102 | * 针对 iOS 系统优化了界面,并支持将快捷方式保存到主屏幕,在全屏模式下打开。 | 105 | SillyTavern 支持扩展。 |
| 103 | * 热键 | ||
| 104 | * 上 = 编辑聊天中的最后一条信息 | ||
| 105 | * Ctrl+P = 编辑聊天中最后一条用户信息 | ||
| 106 | * 左 = 向左滑动 | ||
| 107 | * 右 = 向右滑动(注意:当聊天窗口输入内容时,轻扫快捷键将被禁用) | ||
| 108 | * Ctrl+左 = 查看本地存储的变量(在浏览器控制台窗口中) | ||
| 109 | * 回车(选择聊天栏)= 向人工智能发送信息 | ||
| 110 | * Ctrl+Enter = 重新生成人工智能最后的回复 | ||
| 111 | 106 | ||
| 112 | * 用户名更改和角色删除不再强制重新刷新页面。 | 107 | - 角色情绪表达 |
| 108 | - 聊天记录自动摘要 | ||
| 109 | - 自动 UI 和聊天翻译 | ||
| 110 | - Stable Diffusion/FLUX/DALL-E 图像生成 | ||
| 111 | - AI 回复消息的文本转语音(通过 ElevenLabs、Silero 或操作系统的 TTS) | ||
| 112 | - 网络搜索功能,为您的 Prompt 添加额外的现实世界背景信息 | ||
| 113 | - 更多扩展可从“下载扩展和资源”菜单中下载。 | ||
| 113 | 114 | ||
| 114 | * 增加在页面加载时自动连接 API 的选项。 | 115 | 有关如何使用它们的使用教程,请参阅[文档](https://docs.sillytavern.app/)。 |
| 115 | * 增加选项,在页面加载时自动加载最近的聊天信息。 | ||
| 116 | * 更好的 Tokens 计算器 - 适用于未保存的文字,并显示永久和临时 Tokens 数量 | ||
| 117 | 116 | ||
| 118 | * 更好的聊天历史查询窗口 | 117 | ## ⌛ 安装 |
| 119 | * 聊天的文件名以"(角色卡名称)+(创建时间)"的可读格式保存 | ||
| 120 | * 聊天历史预览从 40 个字符增加到 300 个字符。 | ||
| 121 | * 聊天历史排序有多种选择(按名称、创建日期、聊天记录大小)。 | ||
| 122 | 118 | ||
| 123 | * 默认情况下,左侧和右侧弹出的设置面板会在点击其他区域时自动关闭。 | 119 | ### 🪟 Windows |
| 124 | * 点击导航面板上的 "锁按钮" 将保持弹出面板打开,并在不同聊天中记住此设置。 | ||
| 125 | * 导航面板的打开或关闭状态也会跨聊天保存。 | ||
| 126 | 120 | ||
| 127 | * 自定义聊天界面: | 121 | > \[!WARNING] |
| 128 | * 收到新消息时播放提示音 | 122 | > |
| 129 | * 切换圆形或长方形头像样式 | 123 | > - 请勿安装到任何受 Windows 控制的文件夹(Program Files、System32 等)中。 |
| 130 | * 在台式电脑上拥有更宽的聊天窗口 | 124 | > - 请勿以管理员权限运行 Start.bat |
| 131 | * 可选的半透明玻璃效果聊天窗口 | 125 | > - 无法在 Windows 7 上安装,因为它无法运行 NodeJS 18.16 |
| 132 | * 可定制 "主文本"、"引用文本 "和 "斜体文本 "的字体颜色。 | ||
| 133 | * 可定制聊天界面的背景颜色和透明模糊程度 | ||
| 134 | 126 | ||
| 135 | ## 安装 | 127 | #### 通过 Git 安装(推荐) |
| 136 | 128 | ||
| 137 | *注意:SillyTavern 用于本地安装,尚未在 Colab 或其他云服务上进行全面测试。 | 129 | 1. 安装 [NodeJS](https://nodejs.org/en)(建议使用最新的 LTS 版本) |
| 130 | 2. 安装 [Git for Windows](https://gitforwindows.org/) | ||
| 131 | 3. 打开 Windows 资源管理器 (`Win+E`) | ||
| 132 | 4. 浏览或创建一个不受 Windows 控制或监控的文件夹(例如:C:\MySpecialFolder\) | ||
| 133 | 5. 通过点击顶部的“地址栏”,输入 `cmd`,然后按 Enter,在该文件夹内打开命令提示符。 | ||
| 134 | 6. 弹出黑框(命令提示符)后,键入以下其中一项并按 Enter: | ||
| 138 | 135 | ||
| 139 | > **警告** | 136 | - Release 分支:`git clone https://github.com/SillyTavern/SillyTavern -b release` |
| 137 | - Staging 分支: `git clone https://github.com/SillyTavern/SillyTavern -b staging` | ||
| 140 | 138 | ||
| 141 | > 切勿安装到任何受 Windows 控制的系统文件夹(Program Files, System32, etc)中。 | 139 | 7. 等待所有内容克隆完成后,双击 `Start.bat` 以使 NodeJS 安装其依赖项。 |
| 140 | 8. 然后服务器将启动,SillyTavern 将在您的浏览器中弹出。 | ||
| 142 | 141 | ||
| 143 | > 不要以管理员权限运行 start.bat | 142 | #### 通过 GitHub Desktop 安装 |
| 144 | 143 | ||
| 145 | ### Windows | 144 | (这**仅**允许在 GitHub Desktop 中使用 git,如果您也想在命令行上使用 `git`,则还需要安装 [Git for Windows](https://gitforwindows.org/)) |
| 146 | 145 | ||
| 147 | 通过 Git 安装(推荐使用,便于更新) | 146 | 1. 安装 [NodeJS](https://nodejs.org/en)(建议使用最新的 LTS 版本) |
| 147 | 2. 安装 [GitHub Desktop](https://central.github.com/deployments/desktop/desktop/latest/win32) | ||
| 148 | 3. 安装 GitHub Desktop 后,点击 `Clone a repository from the internet....`(注意:此步骤**无需**创建 GitHub 帐户) | ||
| 149 | 4. 在菜单中,点击 URL 选项卡,输入此 URL `https://github.com/SillyTavern/SillyTavern`,然后点击 Clone。您可以更改本地路径以更改 SillyTavern 的下载位置。 | ||
| 150 | 5. 要打开 SillyTavern,请使用 Windows 资源管理器浏览到克隆存储库的文件夹。默认情况下,存储库将克隆到此处:`C:\Users\[您的 Windows 用户名]\Documents\GitHub\SillyTavern` | ||
| 151 | 6. 双击 `start.bat` 文件。(注意:文件名的 `.bat` 部分可能被您的操作系统隐藏,在这种情况下,它将显示为一个名为“`Start`”的文件。双击此文件以运行 SillyTavern) | ||
| 152 | 7. 双击后,应打开一个大的黑色命令控制台窗口,SillyTavern 将开始安装其运行所需的组件。 | ||
| 153 | 8. 安装过程完成后,如果一切正常,命令控制台窗口应如下所示,并且您的浏览器中应打开一个 SillyTavern 选项卡: | ||
| 154 | 9. 连接到任何[支持的 API](https://docs.sillytavern.app/usage/api-connections/) 并开始聊天! | ||
| 148 | 155 | ||
| 149 | 附有精美图片示例的简易指南: | 156 | ### 🐧 Linux & 🍎 MacOS |
| 150 | <https://docs.sillytavern.app/installation/windows/> | ||
| 151 | 157 | ||
| 152 | 1. 安装 [NodeJS](https://nodejs.org/en)(建议使用最新的 LTS 版本) | 158 | 对于 MacOS / Linux,所有这些都将在终端中完成。 |
| 153 | 2. 安装 [GitHub 客户端](https://central.github.com/deployments/desktop/desktop/latest/win32) | ||
| 154 | 3. 打开 Windows 资源管理器 (`Win+E`) | ||
| 155 | 4. 浏览或创建一个不受 Windows 控制或监控的文件夹。(例如:C:\MySpecialFolder\) | ||
| 156 | 5. 点击顶部的 "地址栏",在该文件夹内打开命令提示符,输入 `cmd`,然后按回车。 | ||
| 157 | 6. 弹出黑框(CMD 命令提示符)后,键入以下其中一项并按 Enter: | ||
| 158 | 159 | ||
| 159 | * 稳定分支:`git clone https://github.com/SillyTavern/SillyTavern -b release` | 160 | 1. 安装 git 和 nodeJS(具体方法取决于您的操作系统) |
| 160 | * 开发分支: `git clone https://github.com/SillyTavern/SillyTavern -b staging` | 161 | 2. 克隆仓库 |
| 161 | 162 | ||
| 162 | 7. 等待 Git 克隆完成后,双击文件夹中的 `Start.bat` 将启动 NodeJS 并开始自动安装需要的软件包。 | 163 | - Release 分支:`git clone https://github.com/SillyTavern/SillyTavern -b release` |
| 163 | 8. 然后 SillyTavern 服务就会自动启动,同时在浏览器新标签页中自动打开。 | 164 | - Staging 分支: `git clone https://github.com/SillyTavern/SillyTavern -b staging` |
| 164 | 165 | ||
| 165 | 通过压缩包下载安装(不推荐) | 166 | 3. `cd SillyTavern` 导航到安装文件夹。 |
| 167 | 4. 使用以下命令之一运行 `start.sh` 脚本: | ||
| 166 | 168 | ||
| 167 | 1. 安装 [NodeJS](https://nodejs.org/en)(建议使用最新的 LTS 版本) | 169 | - `./start.sh` |
| 168 | 2. 从该 GitHub 仓库下载压缩包。(从 [Releases](https://github.com/SillyTavern/SillyTavern/releases/latest) 获取 "Source code(zip)")。 | 170 | - `bash start.sh` |
| 169 | 3. 将压缩包解压到您选择的文件夹中 | ||
| 170 | 4. 双击或在命令行中运行 `Start.bat`。 | ||
| 171 | 5. SillyTavern 服务自动为你准备好一切后,会在你的浏览器中打开一个新标签页。 | ||
| 172 | 171 | ||
| 173 | ### Linux | 172 | ## 🐋 通过 Docker 安装 |
| 174 | 173 | ||
| 175 | 1.运行 `start.sh` 脚本。 | 174 | 这些说明假定您已安装 Docker,能够访问命令行以安装容器,并熟悉其常规操作。 |
| 176 | 2.等待自动完成,然后开始享受 | ||
| 177 | 175 | ||
| 178 | ## API 密钥管理 | 176 | ### 使用 GitHub Container Registry |
| 179 | 177 | ||
| 180 | SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。 | 178 | #### Docker Compose (最简单) |
| 181 | 179 | ||
| 182 | 默认情况下,输入密钥并重新加载页面后,密钥会自动隐藏以保证安全。 | 180 | 从 [GitHub 仓库](https://github.com/SillyTavern/SillyTavern/blob/release/docker/docker-compose.yml) 获取 `docker-compose.yml` 文件,并在文件所在目录中运行以下命令。这将从 GitHub Container Registry 中拉取最新的 release 镜像并启动容器,自动创建必要的卷。 |
| 183 | 181 | ||
| 184 | 如果要想通过点击 API 输入框旁边的按钮来查看密钥,请按照以下设置: | 182 | ```shell |
| 183 | docker-compose up | ||
| 184 | ``` | ||
| 185 | 185 | ||
| 186 | 1. 打开 `config.yaml` 文件,将里面的 `allowKeysExposure` 设置为 `true`。 | 186 | 根据您的需求自定义 `docker-compose.yml` 文件。默认端口为 8000。如果您想使用环境变量调整服务器配置,请在此处阅读文档:[链接](https://docs.sillytavern.app/administration/config-yaml/#environment-variables)。 |
| 187 | 2. 然后重启 SillyTavern 服务。 | ||
| 188 | 187 | ||
| 189 | ## 远程访问 | 188 | #### Docker CLI (高级) |
| 190 | 189 | ||
| 191 | 这通常是为那些想在手机上使用 SillyTavern 的人准备的,而他们的电脑和手机在同一个局域网中。 | 190 | 您将需要两个强制性的目录映射和一个端口映射才能使 SillyTavern 正常运行。在命令中,替换以下位置中的选项: |
| 192 | 191 | ||
| 193 | 不过,SillyTavern 也可以被设置为允许从任何地方进行远程访问。 | 192 | #### 容器变量 |
| 194 | 193 | ||
| 195 | **重要提示:SillyTavern 是单用户程序,因此任何人登录后都能看到所有的角色卡和聊天内容,并能更改任何设置。 | 194 | ##### 卷映射 |
| 196 | 195 | ||
| 197 | ### 1.管理白名单 IP | 196 | - `CONFIG_PATH` - SillyTavern 配置文件将存储在主机上的目录 |
| 197 | - `DATA_PATH` - SillyTavern 用户数据(包括角色)将存储在主机上的目录 | ||
| 198 | - `PLUGINS_PATH` - (可选) SillyTavern 服务器插件将存储在主机上的目录 | ||
| 199 | - `EXTENSIONS_PATH` - (可选) 全局 UI 扩展将存储在主机上的目录 | ||
| 198 | 200 | ||
| 199 | * 在你的 SillyTavern 文件夹中新建一个文本文件,名为 `whitelist.txt`。 | 201 | ##### 端口映射 |
| 200 | * 用文本编辑器打开该文件,添加你希望允许连接的 IP 地址列表。 | ||
| 201 | * 接受单个 IP 地址和 IP 范围,示例: | ||
| 202 | 202 | ||
| 203 | ``` | 203 | - `PUBLIC_PORT` - 暴露流量的端口。这是强制性的,因为您将从其虚拟机容器外部访问实例。**在未实现单独的安全服务的情况下,请勿将其暴露给互联网。** |
| 204 | 192.168.0.1 | ||
| 205 | 192.168.0.20 | ||
| 206 | ``` | ||
| 207 | 204 | ||
| 208 | 或者 | 205 | ##### 附加设置 |
| 209 | 206 | ||
| 210 | ``` | 207 | - `SILLYTAVERN_VERSION` - 在此 GitHub 页面的右侧,您会看到“Packages”。选择“sillytavern”包,您将看到镜像版本。镜像标签“latest”将使您与当前 release 保持同步。您还可以使用指向相应分支的每日镜像的“staging”标签。 |
| 211 | 192.168.0.* | ||
| 212 | ``` | ||
| 213 | 208 | ||
| 214 | (上述 IP 范围将允许局域网中的任何设备连接) | 209 | #### 运行容器 |
| 215 | 210 | ||
| 216 | 也接受子网掩码设置(如 10.0.0.0/24)。 | 211 | 1. 打开您的命令行 |
| 212 | 2. 在您要存储配置和数据文件的文件夹中运行以下命令: | ||
| 217 | 213 | ||
| 218 | * 保存`whitelist.txt`文件。 | 214 | ```bash |
| 219 | * 重启 SillyTavern 服务。 | 215 | SILLYTAVERN_VERSION="latest" |
| 216 | PUBLIC_PORT="8000" | ||
| 217 | CONFIG_PATH="./config" | ||
| 218 | DATA_PATH="./data" | ||
| 219 | PLUGINS_PATH="./plugins" | ||
| 220 | EXTENSIONS_PATH="./extensions" | ||
| 220 | 221 | ||
| 221 | 然后,文件中设置的 IP 就可以访问 SillyTavern 了。 | 222 | docker run \ |
| 223 | --name="sillytavern" \ | ||
| 224 | -p "$PUBLIC_PORT:8000/tcp" \ | ||
| 225 | -v "$CONFIG_PATH:/home/node/app/config:rw" \ | ||
| 226 | -v "$DATA_PATH:/home/node/app/data:rw" \ | ||
| 227 | -v "$EXTENSIONS_PATH:/home/node/app/public/scripts/extensions/third-party:rw" \ | ||
| 228 | -v "$PLUGINS_PATH:/home/node/app/plugins:rw" \ | ||
| 229 | ghcr.io/sillytavern/sillytavern:"$SILLYTAVERN_VERSION" | ||
| 230 | ``` | ||
| 222 | 231 | ||
| 223 | *注意:"config.yaml" 文件内也有一个 "whitelist" 设置,你可以用同样的方法设置它,但如果 "whitelist.txt" 文件存在,这个设置将被忽略。 | 232 | > 默认情况下,容器将在前台运行。如果要在后台运行它,请将 `-d` 标志添加到 `docker run` 命令中。 |
| 224 | 233 | ||
| 225 | ### 2.获取 SillyTavern 服务的 IP 地址 | 234 | ### 自己构建镜像 |
| 226 | 235 | ||
| 227 | 白名单设置完成后,您需要 SillyTavern 服务的 IP 地址。 | 236 | 我们有一个关于在 Docker 中使用 SillyTavern 的综合指南[在此处](http://docs.sillytavern.app/installation/docker/),涵盖了 Windows、macOS 和 Linux 上的安装!如果您希望自己构建镜像,请阅读它。 |
| 228 | 237 | ||
| 229 | 如果 SillyTavern 服务设备在同一个局域网上,则使用安装 SillyTavern 服务的电脑的局域网 IP 地址: | 238 | ## ⚡ 通过 SillyTavern Launcher 安装 |
| 230 | 239 | ||
| 231 | * Windows:Windows 按钮 > 在搜索栏中输入 `cmd.exe` > 在打开的控制台中输入 `ipconfig`,回车 > 然后在输出中查找 `IPv4` 地址。 | 240 | SillyTavern Launcher 是一个安装向导,可帮助您进行多种选项的设置,包括为本地推理安装后端。 |
| 232 | 241 | ||
| 233 | 如果您(或其他人)想在互联网中访问你自己的 SillyTavern 服务,则需要运行 SillyTavern 服务的设备的互联网 IP 地址。 | 242 | ### 对于 Windows 用户 |
| 234 | 243 | ||
| 235 | * 使用运行 SillyTavern 的设备,访问 [this page](https://whatismyipaddress.com/) 并查找 `IPv4`。这是您从互联网访问时要用到的。 | 244 | 1. 在键盘上:按 **`WINDOWS + R`** 打开“运行”对话框。然后,运行以下命令安装 git: |
| 236 | 245 | ||
| 237 | ### 3. 使用其他设备访问 SillyTavern 服务 | 246 | ```shell |
| 247 | cmd /c winget install -e --id Git.Git | ||
| 248 | ``` | ||
| 238 | 249 | ||
| 239 | 无论你最终使用的是什么 IP 地址,都要将该 IP 地址和端口号输入其他设备网络浏览器。 | 250 | 2. 在键盘上:按 **`WINDOWS + E`** 打开文件资源管理器,然后导航到要安装启动器的文件夹。进入所需文件夹后,在地址栏中键入 `cmd` 并按 Enter。然后,运行以下命令: |
| 240 | 251 | ||
| 241 | 同一局域网中的 SillyTavern 服务的典型默认地址如下: | 252 | ```shell |
| 253 | git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher && start installer.bat | ||
| 254 | ``` | ||
| 242 | 255 | ||
| 243 | `http://192.168.0.5:8000` | 256 | ### 对于 Linux 用户 |
| 244 | 257 | ||
| 245 | 使用 http:// 而不是 https:// | 258 | 1. 打开您喜欢的终端并安装 git |
| 259 | 2. 使用以下命令克隆 SillyTavern-Launcher: | ||
| 246 | 260 | ||
| 247 | ### 向所有 IP 开放您的 SillyTavern 服务 | 261 | ```shell |
| 262 | git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher | ||
| 263 | ``` | ||
| 248 | 264 | ||
| 249 | 我们不建议这样做,但您可以打开 `config.yaml` 并将里面的 `whitelistMode` 设置改为 `false`。 | 265 | 3. 使用以下命令启动 installer.sh: |
| 250 | 266 | ||
| 251 | 你必须删除(或重命名)SillyTavern 文件夹中的 `whitelist.txt` 文件(如果有的话)。 | 267 | ```shell |
| 268 | chmod +x install.sh && ./install.sh | ||
| 269 | ``` | ||
| 252 | 270 | ||
| 253 | 这通常是不安全的做法,所以我们要求在这样做时必须设置用户名和密码。 | 271 | 4. 安装后使用以下命令启动 launcher.sh: |
| 254 | 272 | ||
| 255 | 用户名和密码在`config.yaml`文件中设置。 | 273 | ```shell |
| 274 | chmod +x launcher.sh && ./launcher.sh | ||
| 275 | ``` | ||
| 256 | 276 | ||
| 257 | 重启 SillyTavern 服务后,只要知道用户名和密码,任何设备都可以访问。 | 277 | ### 对于 Mac 用户 |
| 258 | 278 | ||
| 259 | ### 还是无法访问? | 279 | 1. 打开终端并使用以下命令安装 brew: |
| 260 | 280 | ||
| 261 | * 为 `config.yaml` 文件中的端口创建一条入站/出站防火墙规则。切勿将此误认为是路由器上的端口转发,否则,有人可能会发现你的聊天隐私,那就大错特错了。 | 281 | ```shell |
| 262 | * 在 "设置" > "网络和 Internet" > "以太网" 中启用 "专用网络" 配置。这对 Windows 11 非常重要,否则即使添加了上述防火墙规则也无法连接。 | 282 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" |
| 283 | ``` | ||
| 263 | 284 | ||
| 264 | ### 性能问题? | 285 | 2. 使用以下命令安装 git: |
| 265 | 286 | ||
| 266 | 尝试在用户设置面板上关闭模糊效果(快速用户界面)模式。 | 287 | ```shell |
| 288 | brew install git | ||
| 289 | ``` | ||
| 267 | 290 | ||
| 268 | ## 我喜欢你的项目!我该如何贡献自己的力量? | 291 | 3. 使用以下命令克隆 SillyTavern-Launcher: |
| 269 | 292 | ||
| 270 | ### 应该 | 293 | ```shell |
| 294 | git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher | ||
| 295 | ``` | ||
| 271 | 296 | ||
| 272 | 1. 发送 Fork 请求 | 297 | 4. 使用以下命令启动 installer.sh: |
| 273 | 2. 使用规定的模板发送功能建议和问题报告 | ||
| 274 | 3. 在提出任何问题之前,请先阅读 Readme 文件和文档 | ||
| 275 | 298 | ||
| 276 | #### 不应该 | 299 | ```shell |
| 300 | chmod +x install.sh && ./install.sh | ||
| 301 | ``` | ||
| 277 | 302 | ||
| 278 | 1. 提供金钱捐赠 | 303 | 5. 安装后使用以下命令启动 launcher.sh: |
| 279 | 2. 发送错误报告而不提供任何详细信息 | ||
| 280 | 3. 提出已经回答过无数次的问题 | ||
| 281 | 304 | ||
| 282 | ## 我在哪里可以找到以前的聊天背景图片? | 305 | ```shell |
| 306 | chmod +x launcher.sh && ./launcher.sh | ||
| 307 | ``` | ||
| 283 | 308 | ||
| 284 | 我们正在实行 100% 原创内容的政策,因此旧的背景图片已从该资源库中删除。 | 309 | ## 📱 通过 Termux 在 Android OS 上安装 |
| 285 | 310 | ||
| 286 | 不过你可以在这里找到它们的存档: | 311 | > \[!NOTE] |
| 312 | > **SillyTavern 可以在 Android 设备上使用 Termux 原生运行,但我们不为此用例提供官方支持。** | ||
| 313 | > | ||
| 314 | > **请参阅 ArroganceComplex#2659 编写的本指南:** | ||
| 315 | > | ||
| 316 | > - <https://rentry.org/STAI-Termux> | ||
| 287 | 317 | ||
| 288 | <https://files.catbox.moe/1xevnc.zip> | 318 | **不支持的平台:android arm LEtime-web。** 32 位 Android 需要一个无法通过 npm 安装的外部依赖项。使用以下命令安装它:`pkg install esbuild`。然后运行常规安装步骤。 |
| 289 | 319 | ||
| 290 | ## 屏幕截图 | 320 | ## 命令行参数 |
| 291 | 321 | ||
| 292 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> | 322 | 您可以将命令行参数传递给 SillyTavern 服务器启动脚本,以覆盖 `config.yaml` 中的某些设置。 |
| 293 | <img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> | ||
| 294 | 323 | ||
| 295 | ## 许可证和贡献 | 324 | ### 示例 |
| 296 | 325 | ||
| 297 | **发布本程序是希望它能有所帮助,但不做任何保证;甚至没有明示的性能、稳定性和其他任何特定用途的可用性保证。更多详情,请参阅 GNU Affero 通用公共许可证。** | 326 | ```shell |
| 298 | 327 | node server.js --port 8000 --listen false | |
| 299 | **This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.** | 328 | # 或 |
| 300 | 329 | npm run start -- --port 8000 --listen false | |
| 301 | * TAI Base by Humi: Unknown license | 330 | # 或 (仅限 Windows) |
| 302 | * Cohee's modifications and derived code: AGPL v3 | 331 | Start.bat --port 8000 --listen false |
| 303 | * RossAscends' additions: AGPL v3 | 332 | ``` |
| 304 | * Portions of CncAnon's TavernAITurbo mod: Unknown license | 333 | |
| 305 | * kingbri's various commits and suggestions (<https://github.com/bdashore3>) | 334 | ### 支持的参数 |
| 306 | * StefanDanielSchwarz's various commits and bug reports (<https://github.com/StefanDanielSchwarz>) | 335 | |
| 307 | * Waifu mode inspired by the work of PepperTaco (<https://github.com/peppertaco/Tavern/>) | 336 | > \[!TIP] |
| 308 | * Thanks Pygmalion University for being awesome testers and suggesting cool features! | 337 | > 所有参数都不是必需的。如果您不提供它们,SillyTavern 将使用 `config.yaml` 中的设置。 |
| 309 | * Thanks oobabooga for compiling presets for TextGen | 338 | |
| 310 | * KoboldAI Presets from KAI Lite: <https://lite.koboldai.net/> | 339 | | 选项 | 描述 | 类型 | |
| 311 | * Noto Sans font by Google (OFL license) | 340 | | -------------------------------- | ---------------------------------------------- | ------- | |
| 312 | * Icon theme by Font Awesome <https://fontawesome.com> (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) | 341 | | `--version` | 显示版本号 | boolean | |
| 313 | * AI Horde client library by ZeldaFan0225: <https://github.com/ZeldaFan0225/ai_horde> | 342 | | `--configPath` | 覆盖 config.yaml 文件的路径 | string | |
| 314 | * Linux startup script by AlpinDale | 343 | | `--dataRoot` | 数据存储的根目录 | string | |
| 315 | * Thanks paniphons for providing a FAQ document | 344 | | `--port` | 设置 SillyTavern 将在其下运行的端口 | number | |
| 316 | * 10K Discord Users Celebratory Background by @kallmeflocc | 345 | | `--listen` | SillyTavern 将侦听所有网络接口 | boolean | |
| 317 | * Default content (characters and lore books) provided by @OtisAlejandro, @RossAscends and @kallmeflocc | 346 | | `--whitelist` | 启用白名单模式 | boolean | |
| 318 | * Korean translation by @doloroushyeonse | 347 | | `--basicAuthMode` | 启用基本身份验证 | boolean | |
| 319 | * 中文翻译由 [@XXpE3](https://github.com/XXpE3) 完成,中文 ISSUES 可以联系 @XXpE3 | 348 | | `--enableIPv4` | 启用 IPv4 协议 | boolean | |
| 349 | | `--enableIPv6` | 启用 IPv6 协议 | boolean | | ||
| 350 | | `--listenAddressIPv4` | 要侦听的特定 IPv4 地址 | string | | ||
| 351 | | `--listenAddressIPv6` | 要侦听的特定 IPv6 地址 | string | | ||
| 352 | | `--dnsPreferIPv6` | DNS 首选 IPv6 | boolean | | ||
| 353 | | `--ssl` | 启用 SSL | boolean | | ||
| 354 | | `--certPath` | 您的证书文件路径 | string | | ||
| 355 | | `--keyPath` | 您的私钥文件路径 | string | | ||
| 356 | | `--browserLaunchEnabled` | 自动在浏览器中启动 SillyTavern | boolean | | ||
| 357 | | `--browserLaunchHostname` | 自动运行主机名 | string | | ||
| 358 | | `--browserLaunchPort` | 覆盖自动运行的端口 | string | | ||
| 359 | | `--browserLaunchAvoidLocalhost` | 在自动模式下避免使用 'localhost' 进行自动运行 | boolean | | ||
| 360 | | `--corsProxy` | 启用 CORS 代理 | boolean | | ||
| 361 | | `--requestProxyEnabled` | 为传出请求启用代理 | boolean | | ||
| 362 | | `--requestProxyUrl` | 请求代理 URL(HTTP 或 SOCKS 协议) | string | | ||
| 363 | | `--requestProxyBypass` | 请求代理绕过列表(以空格分隔的主机列表) | array | | ||
| 364 | | `--disableCsrf` | 禁用 CSRF 保护(不推荐) | boolean | | ||
| 365 | |||
| 366 | ## 远程连接 | ||
| 367 | |||
| 368 | 这通常适用于那些想在手机上使用 SillyTavern,而他们的电脑在同一 Wi-Fi 网络上运行 ST 服务器的人。但是,它也可以用于允许从任何地方进行远程连接。 | ||
| 369 | |||
| 370 | 请在[文档](https://docs.sillytavern.app/usage/remoteconnections/)中阅读有关如何设置远程连接的详细指南。 | ||
| 371 | |||
| 372 | 您可能还需要配置 SillyTavern 用户配置文件(可选密码保护):[用户](https://docs.sillytavern.app/administration/multi-user/)。 | ||
| 373 | |||
| 374 | ## 许可证和致谢 | ||
| 375 | |||
| 376 | **本程序的分发是希望它能有用,但不提供任何保证;甚至没有对适销性或特定用途适用性的默示保证。有关更多详细信息,请参阅 GNU Affero 通用公共许可证。** | ||
| 377 | |||
| 378 | - [TavernAI](https://github.com/TavernAI/TavernAI) 1.2.8 by Humi: MIT 许可证 | ||
| 379 | - CncAnon 的 TavernAITurbo mod 的部分内容经许可使用 | ||
| 380 | - 视觉小说模式的灵感来自 PepperTaco 的工作 (<https://github.com/peppertaco/Tavern/>) | ||
| 381 | - Noto Sans 字体 by Google (OFL 许可证) | ||
| 382 | - 图标主题 by Font Awesome <https://fontawesome.com> (图标: CC BY 4.0, 字体: SIL OFL 1.1, 代码: MIT 许可证) | ||
| 383 | - 默认内容由 @OtisAlejandro (Seraphina 角色和世界书) 和 @kallmeflocc (10K Discord 用户庆祝背景) 提供 | ||
| 384 | - Docker 指南由 [@mrguymiah](https://github.com/mrguymiah) 和 [@Bronya-Rand](https://github.com/Bronya-Rand) 提供 | ||
| 385 | - kokoro-js 库由 [@hexgrad](https://github.com/hexgrad) 提供 (Apache-2.0 许可证) | ||
| 386 | - 中文翻译由 [@XXpE3](https://github.com/XXpE3) 完成,中文 ISSUES 可以联系 @XXpE3 | ||
| 387 | |||
| 388 | ## 主要贡献者 | ||
| 389 | |||
| 390 | [](https://github.com/SillyTavern/SillyTavern/graphs/contributors) | ||
| 320 | 391 | ||
| 321 | <!-- LINK GROUP --> | 392 | <!-- LINK GROUP --> |
| 393 | |||
| 322 | [cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 | 394 | [cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 |
| 395 | [discord-link]: https://discord.gg/sillytavern | ||
| 396 | [discord-shield-badge]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge | ||
| @@ -319,29 +319,29 @@ Start.bat --port 8000 --listen false | |||
| 319 | 319 | ||
| 320 | ### Supported arguments | 320 | ### Supported arguments |
| 321 | 321 | ||
| 322 | | Option | Description | Type | | 322 | | Option | Description | Type | |
| 323 | |-------------------------|------------------------------------------------------------------------------------------------------|----------| | 323 | |----------------------------------|---------------------------------------------|---------| |
| 324 | | `--version` | 顯示版本序號 | boolean | | 324 | | `--version` | 顯示版本序號 | boolean | |
| 325 | | `--enableIPv6` | 啟用 IPv6 | boolean | | 325 | | `--enableIPv6` | 啟用 IPv6 | boolean | |
| 326 | | `--enableIPv4` | 啟用 IPv4 | boolean | | 326 | | `--enableIPv4` | 啟用 IPv4 | boolean | |
| 327 | | `--port` | 設定 SillyTavern 運行的端口。若未提供,則預設使用 `config.yaml` 中的 'port' | number | 327 | | `--port` | 設定 SillyTavern 運行的端口。 | number | |
| 328 | | `--dnsPreferIPv6` | 偏好使用 IPv6 解析 DNS。未提供則默認使用 `config.yaml` 中的 'preferIPv6' | boolean | | 328 | | `--dnsPreferIPv6` | 偏好使用 IPv6 解析 DNS。 | boolean | |
| 329 | | `--autorun` | 自動在瀏覽器中啟動 SillyTavern。未提供則默認使用 `config.yaml` 中的 'autorun' | boolean | | 329 | | `--browserLaunchEnabled` | 自動在瀏覽器中啟動 SillyTavern。 | boolean | |
| 330 | | `--autorunHostname` | 自動啟動時的主機名稱,通常建議保持為 'auto' | string | | 330 | | `--browserLaunchHostname` | 自動啟動時的主機名稱,通常建議保持為 'auto' | string | |
| 331 | | `--autorunPortOverride` | 覆蓋自動啟動的端口設定 | string | | 331 | | `--browserLaunchPort` | 覆蓋自動啟動的端口設定 | string | |
| 332 | | `--listen` | SillyTavern 是否可監聽所有網路接口。若未提供,則默認使用 `config.yaml` 中的 'listen' | boolean | | 332 | | `--browserLaunchAvoidLocalhost` | 在自動模式下避免使用 'localhost' | boolean | |
| 333 | | `--corsProxy` | 啟用 CORS 代理。若未提供,則默認使用 `config.yaml` 中的 'enableCorsProxy' | boolean | | 333 | | `--listen` | SillyTavern 是否可監聽所有網路接口。 | boolean | |
| 334 | | `--disableCsrf` | 停用 CSRF 保護 | boolean | | 334 | | `--corsProxy` | 啟用 CORS 代理。 | boolean | |
| 335 | | `--ssl` | 啟用 SSL | boolean | | 335 | | `--disableCsrf` | 停用 CSRF 保護 | boolean | |
| 336 | | `--certPath` | 設定您證書文件的路徑 | string | | 336 | | `--ssl` | 啟用 SSL | boolean | |
| 337 | | `--keyPath` | 設定您私人金鑰文件的路徑 | string | | 337 | | `--certPath` | 設定您證書文件的路徑 | string | |
| 338 | | `--whitelist` | 啟用白名單模式 | boolean | | 338 | | `--keyPath` | 設定您私人金鑰文件的路徑 | string | |
| 339 | | `--dataRoot` | 設定數據儲存的根目錄 | string | | 339 | | `--whitelist` | 啟用白名單模式 | boolean | |
| 340 | | `--avoidLocalhost` | 在自動模式下避免使用 'localhost' | boolean | | 340 | | `--dataRoot` | 設定數據儲存的根目錄 | string | |
| 341 | | `--basicAuthMode` | 啟用基本身份驗證模式 | boolean | | 341 | | `--basicAuthMode` | 啟用基本身份驗證模式 | boolean | |
| 342 | | `--requestProxyEnabled` | 啟用代理以處理外部請求 | boolean | | 342 | | `--requestProxyEnabled` | 啟用代理以處理外部請求 | boolean | |
| 343 | | `--requestProxyUrl` | 設定請求代理的 URL(支持 HTTP 或 SOCKS 協議) | string | | 343 | | `--requestProxyUrl` | 設定請求代理的 URL(支持 HTTP 或 SOCKS 協議)| string | |
| 344 | | `--requestProxyBypass` | 請求代理的例外主機清單(主機列表需以空格分隔) | array | | 344 | | `--requestProxyBypass` | 請求代理的例外主機清單(主機列表需以空格分隔)| array | |
| 345 | 345 | ||
| 346 | ## 遠端連線 | 346 | ## 遠端連線 |
| 347 | 347 | ||
| @@ -232,6 +232,28 @@ docker run \ | |||
| 232 | 232 | ||
| 233 | We have a comprehensive guide on using SillyTavern in Docker [here](http://docs.sillytavern.app/installation/docker/) which covers installations on Windows, macOS and Linux! Give it a read if you wish to build the image yourself. | 233 | We have a comprehensive guide on using SillyTavern in Docker [here](http://docs.sillytavern.app/installation/docker/) which covers installations on Windows, macOS and Linux! Give it a read if you wish to build the image yourself. |
| 234 | 234 | ||
| 235 | ### Common issues with Docker | ||
| 236 | |||
| 237 | #### SELinux Permission Issues with Mounted Volumes | ||
| 238 | |||
| 239 | Linux distributions with SELinux enabled (such as RHEL, CentOS, Fedora, etc.) may prevent Docker containers from accessing mounted volumes due to security policies. This can result in permission denied errors when the container tries to read or write to the mounted directories. | ||
| 240 | |||
| 241 | Two suffixes `:z` or `:Z` can be added to the volume mount. These suffixes tell Docker to relabel file objects on the shared volumes. | ||
| 242 | |||
| 243 | * The `z` option is used when the volume content will be shared between containers. | ||
| 244 | * The `Z` option is used when the volume content should only be used by the current container. | ||
| 245 | |||
| 246 | Example: | ||
| 247 | |||
| 248 | ```yaml | ||
| 249 | # docker-compose.yml | ||
| 250 | volumes: | ||
| 251 | ## Shared volume | ||
| 252 | - ./config:/home/node/app/config:z | ||
| 253 | ## Private volume | ||
| 254 | - ./data:/home/node/app/data:Z | ||
| 255 | ``` | ||
| 256 | |||
| 235 | ## ⚡ Installing via SillyTavern Launcher | 257 | ## ⚡ Installing via SillyTavern Launcher |
| 236 | 258 | ||
| 237 | SillyTavern Launcher is an installation wizard that will help you get setup with many options, including installing a backend for local inference. | 259 | SillyTavern Launcher is an installation wizard that will help you get setup with many options, including installing a backend for local inference. |
| @@ -333,32 +355,32 @@ Start.bat --port 8000 --listen false | |||
| 333 | > \[!TIP] | 355 | > \[!TIP] |
| 334 | > None of the arguments are required. If you don't provide them, SillyTavern will use the settings in `config.yaml`. | 356 | > None of the arguments are required. If you don't provide them, SillyTavern will use the settings in `config.yaml`. |
| 335 | 357 | ||
| 336 | | Option | Description | Type | | 358 | | Option | Description | Type | |
| 337 | |-------------------------|----------------------------------------------------------------------|----------| | 359 | |---------------------------------|----------------------------------------------------------------------|----------| |
| 338 | | `--version` | Show version number | boolean | | 360 | | `--version` | Show version number | boolean | |
| 339 | | `--configPath` | Override the path to the config.yaml file | string | | 361 | | `--configPath` | Override the path to the config.yaml file | string | |
| 340 | | `--dataRoot` | Root directory for data storage | string | | 362 | | `--dataRoot` | Root directory for data storage | string | |
| 341 | | `--port` | Sets the port under which SillyTavern will run | number | | 363 | | `--port` | Sets the port under which SillyTavern will run | number | |
| 342 | | `--listen` | SillyTavern will listen on all network interfaces | boolean | | 364 | | `--listen` | SillyTavern will listen on all network interfaces | boolean | |
| 343 | | `--whitelist` | Enables whitelist mode | boolean | | 365 | | `--whitelist` | Enables whitelist mode | boolean | |
| 344 | | `--basicAuthMode` | Enables basic authentication | boolean | | 366 | | `--basicAuthMode` | Enables basic authentication | boolean | |
| 345 | | `--enableIPv4` | Enables IPv4 protocol | boolean | | 367 | | `--enableIPv4` | Enables IPv4 protocol | boolean | |
| 346 | | `--enableIPv6` | Enables IPv6 protocol | boolean | | 368 | | `--enableIPv6` | Enables IPv6 protocol | boolean | |
| 347 | | `--listenAddressIPv4` | Specific IPv4 address to listen to | string | | 369 | | `--listenAddressIPv4` | Specific IPv4 address to listen to | string | |
| 348 | | `--listenAddressIPv6` | Specific IPv6 address to listen to | string | | 370 | | `--listenAddressIPv6` | Specific IPv6 address to listen to | string | |
| 349 | | `--dnsPreferIPv6` | Prefers IPv6 for DNS | boolean | | 371 | | `--dnsPreferIPv6` | Prefers IPv6 for DNS | boolean | |
| 350 | | `--ssl` | Enables SSL | boolean | | 372 | | `--ssl` | Enables SSL | boolean | |
| 351 | | `--certPath` | Path to your certificate file | string | | 373 | | `--certPath` | Path to your certificate file | string | |
| 352 | | `--keyPath` | Path to your private key file | string | | 374 | | `--keyPath` | Path to your private key file | string | |
| 353 | | `--autorun` | Automatically launch SillyTavern in the browser | boolean | | 375 | | `--browserLaunchEnabled` | Automatically launch SillyTavern in the browser | boolean | |
| 354 | | `--autorunHostname` | Autorun hostname | string | | 376 | | `--browserLaunchHostname` | Browser launch hostname | string | |
| 355 | | `--autorunPortOverride` | Overrides the port for autorun | string | | 377 | | `--browserLaunchPort` | Overrides the port for browser launch | string | |
| 356 | | `--avoidLocalhost` | Avoids using 'localhost' for autorun in auto mode | boolean | | 378 | | `--browserLaunchAvoidLocalhost` | Avoids using 'localhost' for browser launch in auto mode | boolean | |
| 357 | | `--corsProxy` | Enables CORS proxy | boolean | | 379 | | `--corsProxy` | Enables CORS proxy | boolean | |
| 358 | | `--requestProxyEnabled` | Enables a use of proxy for outgoing requests | boolean | | 380 | | `--requestProxyEnabled` | Enables a use of proxy for outgoing requests | boolean | |
| 359 | | `--requestProxyUrl` | Request proxy URL (HTTP or SOCKS protocols) | string | | 381 | | `--requestProxyUrl` | Request proxy URL (HTTP or SOCKS protocols) | string | |
| 360 | | `--requestProxyBypass` | Request proxy bypass list (space separated list of hosts) | array | | 382 | | `--requestProxyBypass` | Request proxy bypass list (space separated list of hosts) | array | |
| 361 | | `--disableCsrf` | Disables CSRF protection (NOT RECOMMENDED) | boolean | | 383 | | `--disableCsrf` | Disables CSRF protection (NOT RECOMMENDED) | boolean | |
| 362 | 384 | ||
| 363 | ## Remote connections | 385 | ## Remote connections |
| 364 | 386 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | FROM node:lts-alpine3.19 | 1 | FROM node:lts-alpine3.21 |
| 2 | 2 | ||
| 3 | # Arguments | 3 | # Arguments |
| 4 | ARG APP_HOME=/home/node/app | 4 | ARG APP_HOME=/home/node/app |
| @@ -19,7 +19,7 @@ RUN \ | |||
| 19 | echo "*** Install npm packages ***" && \ | 19 | echo "*** Install npm packages ***" && \ |
| 20 | npm i --no-audit --no-fund --loglevel=error --no-progress --omit=dev && npm cache clean --force | 20 | npm i --no-audit --no-fund --loglevel=error --no-progress --omit=dev && npm cache clean --force |
| 21 | 21 | ||
| 22 | # Copy default chats, characters and user avatars to <folder>.default folder | 22 | # Create config directory and link config.yaml |
| 23 | RUN \ | 23 | RUN \ |
| 24 | rm -f "config.yaml" || true && \ | 24 | rm -f "config.yaml" || true && \ |
| 25 | ln -s "./config/config.yaml" "config.yaml" || true && \ | 25 | ln -s "./config/config.yaml" "config.yaml" || true && \ |
| @@ -30,7 +30,7 @@ RUN \ | |||
| 30 | echo "*** Run Webpack ***" && \ | 30 | echo "*** Run Webpack ***" && \ |
| 31 | node "./docker/build-lib.js" | 31 | node "./docker/build-lib.js" |
| 32 | 32 | ||
| 33 | # Cleanup unnecessary files | 33 | # Set the entrypoint script |
| 34 | RUN \ | 34 | RUN \ |
| 35 | echo "*** Cleanup ***" && \ | 35 | echo "*** Cleanup ***" && \ |
| 36 | mv "./docker/docker-entrypoint.sh" "./" && \ | 36 | mv "./docker/docker-entrypoint.sh" "./" && \ |
| @@ -16,16 +16,28 @@ protocol: | |||
| 16 | ipv6: false | 16 | ipv6: false |
| 17 | # Prefers IPv6 for DNS. Enable this on ISPs that don't have issues with IPv6 | 17 | # Prefers IPv6 for DNS. Enable this on ISPs that don't have issues with IPv6 |
| 18 | dnsPreferIPv6: false | 18 | dnsPreferIPv6: false |
| 19 | # The hostname that autorun opens. | 19 | # -- BROWSER LAUNCH CONFIGURATION -- |
| 20 | # - Use "auto" to let the server decide | 20 | browserLaunch: |
| 21 | # - Use options like 'localhost', 'st.example.com' | 21 | # Open the browser automatically on server startup. |
| 22 | autorunHostname: "auto" | 22 | enabled: true |
| 23 | # Browser to use for opening the URL. | ||
| 24 | # NOT SUPPORTED ON ANDROID DEVICES. | ||
| 25 | # - Use "default" to use the system default browser | ||
| 26 | # - Use "firefox", "chrome", "edge" | ||
| 27 | browser: 'default' | ||
| 28 | # Overrides the hostname that opens in the browser. | ||
| 29 | # - Use "auto" to let the server decide | ||
| 30 | # - Use options like 'localhost', 'st.example.com' | ||
| 31 | hostname: 'auto' | ||
| 32 | # Overrides the port for run in the browser. | ||
| 33 | # - Use -1 to use the server port. | ||
| 34 | # - Specify a port to override the default. | ||
| 35 | port: -1 | ||
| 36 | # Avoids using 'localhost' as the hostname in auto mode. | ||
| 37 | # Use if you don't have 'localhost' in your hosts file | ||
| 38 | avoidLocalhost: false | ||
| 23 | # Server port | 39 | # Server port |
| 24 | port: 8000 | 40 | port: 8000 |
| 25 | # Overrides the port for autorun in browser. | ||
| 26 | # - Use -1 to use the server port. | ||
| 27 | # - Specify a port to override the default. | ||
| 28 | autorunPortOverride: -1 | ||
| 29 | # -- SSL options -- | 41 | # -- SSL options -- |
| 30 | ssl: | 42 | ssl: |
| 31 | enabled: false | 43 | enabled: false |
| @@ -70,7 +82,7 @@ enableDiscreetLogin: false | |||
| 70 | # https://www.authelia.com/ | 82 | # https://www.authelia.com/ |
| 71 | # This will use auto login to an account with the same username | 83 | # This will use auto login to an account with the same username |
| 72 | # as that used for authlia. (Ensure the username in authlia | 84 | # as that used for authlia. (Ensure the username in authlia |
| 73 | # is an exact match with that in sillytavern) | 85 | # is an exact match in lowercase with that in sillytavern) |
| 74 | autheliaAuth: false | 86 | autheliaAuth: false |
| 75 | # If `basicAuthMode` and this are enabled then | 87 | # If `basicAuthMode` and this are enabled then |
| 76 | # the username and passwords for basic auth are the same as those | 88 | # the username and passwords for basic auth are the same as those |
| @@ -98,12 +110,6 @@ rateLimiting: | |||
| 98 | # Use X-Real-IP header instead of socket IP for rate limiting | 110 | # Use X-Real-IP header instead of socket IP for rate limiting |
| 99 | # Only enable this if you are using a properly configured reverse proxy (like Nginx/traefik/Caddy) | 111 | # Only enable this if you are using a properly configured reverse proxy (like Nginx/traefik/Caddy) |
| 100 | preferRealIpHeader: false | 112 | preferRealIpHeader: false |
| 101 | # -- ADVANCED CONFIGURATION -- | ||
| 102 | # Open the browser automatically | ||
| 103 | autorun: true | ||
| 104 | # Avoids using 'localhost' for autorun in auto mode. | ||
| 105 | # use if you don't have 'localhost' in your hosts file | ||
| 106 | avoidLocalhost: false | ||
| 107 | 113 | ||
| 108 | ## BACKUP CONFIGURATION | 114 | ## BACKUP CONFIGURATION |
| 109 | backups: | 115 | backups: |
| @@ -810,5 +810,13 @@ | |||
| 810 | { | 810 | { |
| 811 | "filename": "presets/reasoning/Blank.json", | 811 | "filename": "presets/reasoning/Blank.json", |
| 812 | "type": "reasoning" | 812 | "type": "reasoning" |
| 813 | }, | ||
| 814 | { | ||
| 815 | "filename": "presets/instruct/Dots1.json", | ||
| 816 | "type": "instruct" | ||
| 817 | }, | ||
| 818 | { | ||
| 819 | "filename": "presets/context/Dots1.json", | ||
| 820 | "type": "context" | ||
| 813 | } | 821 | } |
| 814 | ] | 822 | ] |
| @@ -0,0 +1,11 @@ | |||
| 1 | { | ||
| 2 | "story_string": "<|system|>\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}<|endofsystem|>", | ||
| 3 | "example_separator": "", | ||
| 4 | "chat_start": "", | ||
| 5 | "use_stop_strings": false, | ||
| 6 | "names_as_stop_strings": true, | ||
| 7 | "always_force_name2": true, | ||
| 8 | "trim_sentences": false, | ||
| 9 | "single_line": false, | ||
| 10 | "name": "Dots1" | ||
| 11 | } | ||
| \ No newline at end of file | 11 | \ No newline at end of file | |
| @@ -0,0 +1,24 @@ | |||
| 1 | { | ||
| 2 | "input_sequence": "<|userprompt|>", | ||
| 3 | "output_sequence": "<|response|>", | ||
| 4 | "last_output_sequence": "", | ||
| 5 | "system_sequence": "<|system|>", | ||
| 6 | "stop_sequence": "<|endofresponse|>", | ||
| 7 | "wrap": true, | ||
| 8 | "macro": true, | ||
| 9 | "names_behavior": "force", | ||
| 10 | "activation_regex": "", | ||
| 11 | "system_sequence_prefix": "", | ||
| 12 | "system_sequence_suffix": "", | ||
| 13 | "first_output_sequence": "", | ||
| 14 | "skip_examples": false, | ||
| 15 | "output_suffix": "<|endofresponse|>\n", | ||
| 16 | "input_suffix": "<|endofuserprompt|>\n", | ||
| 17 | "system_suffix": "<|endofsystem|>\n", | ||
| 18 | "user_alignment_message": "", | ||
| 19 | "system_same_as_user": false, | ||
| 20 | "last_system_sequence": "", | ||
| 21 | "first_input_sequence": "", | ||
| 22 | "last_input_sequence": "", | ||
| 23 | "name": "Dots1" | ||
| 24 | } | ||
| @@ -1,16 +1,16 @@ | |||
| 1 | { | 1 | { |
| 2 | "name": "sillytavern", | 2 | "name": "sillytavern", |
| 3 | "version": "1.13.0", | 3 | "version": "1.13.1", |
| 4 | "lockfileVersion": 3, | 4 | "lockfileVersion": 3, |
| 5 | "requires": true, | 5 | "requires": true, |
| 6 | "packages": { | 6 | "packages": { |
| 7 | "": { | 7 | "": { |
| 8 | "name": "sillytavern", | 8 | "name": "sillytavern", |
| 9 | "version": "1.13.0", | 9 | "version": "1.13.1", |
| 10 | "hasInstallScript": true, | 10 | "hasInstallScript": true, |
| 11 | "license": "AGPL-3.0", | 11 | "license": "AGPL-3.0", |
| 12 | "dependencies": { | 12 | "dependencies": { |
| 13 | "@adobe/css-tools": "^4.4.2", | 13 | "@adobe/css-tools": "^4.4.3", |
| 14 | "@agnai/sentencepiece-js": "^1.1.1", | 14 | "@agnai/sentencepiece-js": "^1.1.1", |
| 15 | "@agnai/web-tokenizers": "^0.1.3", | 15 | "@agnai/web-tokenizers": "^0.1.3", |
| 16 | "@iconfu/svg-inject": "^1.2.3", | 16 | "@iconfu/svg-inject": "^1.2.3", |
| @@ -51,19 +51,19 @@ | |||
| 51 | "cookie-session": "^2.1.0", | 51 | "cookie-session": "^2.1.0", |
| 52 | "cors": "^2.8.5", | 52 | "cors": "^2.8.5", |
| 53 | "crc": "^4.3.2", | 53 | "crc": "^4.3.2", |
| 54 | "csrf-sync": "^4.0.3", | 54 | "csrf-sync": "^4.2.1", |
| 55 | "diff-match-patch": "^1.0.5", | 55 | "diff-match-patch": "^1.0.5", |
| 56 | "dompurify": "^3.2.4", | 56 | "dompurify": "^3.2.6", |
| 57 | "droll": "^0.2.1", | 57 | "droll": "^0.2.1", |
| 58 | "express": "^4.21.0", | 58 | "express": "^4.21.0", |
| 59 | "form-data": "^4.0.2", | 59 | "form-data": "^4.0.3", |
| 60 | "fuse.js": "^7.1.0", | 60 | "fuse.js": "^7.1.0", |
| 61 | "google-translate-api-browser": "^3.0.1", | 61 | "google-translate-api-browser": "^3.0.1", |
| 62 | "google-translate-api-x": "^10.7.2", | 62 | "google-translate-api-x": "^10.7.2", |
| 63 | "handlebars": "^4.7.8", | 63 | "handlebars": "^4.7.8", |
| 64 | "helmet": "^7.2.0", | 64 | "helmet": "^8.1.0", |
| 65 | "highlight.js": "^11.11.1", | 65 | "highlight.js": "^11.11.1", |
| 66 | "html-entities": "^2.5.2", | 66 | "html-entities": "^2.6.0", |
| 67 | "iconv-lite": "^0.6.3", | 67 | "iconv-lite": "^0.6.3", |
| 68 | "ip-matching": "^2.1.2", | 68 | "ip-matching": "^2.1.2", |
| 69 | "ip-regex": "^5.0.0", | 69 | "ip-regex": "^5.0.0", |
| @@ -71,13 +71,13 @@ | |||
| 71 | "is-docker": "^3.0.0", | 71 | "is-docker": "^3.0.0", |
| 72 | "localforage": "^1.10.0", | 72 | "localforage": "^1.10.0", |
| 73 | "lodash": "^4.17.21", | 73 | "lodash": "^4.17.21", |
| 74 | "mime-types": "^2.1.35", | 74 | "mime-types": "^3.0.1", |
| 75 | "moment": "^2.30.1", | 75 | "moment": "^2.30.1", |
| 76 | "morphdom": "^2.7.4", | 76 | "morphdom": "^2.7.5", |
| 77 | "multer": "^2.0.1", | 77 | "multer": "^2.0.1", |
| 78 | "node-fetch": "^3.3.2", | 78 | "node-fetch": "^3.3.2", |
| 79 | "node-persist": "^4.0.4", | 79 | "node-persist": "^4.0.4", |
| 80 | "open": "^8.4.2", | 80 | "open": "^10.1.2", |
| 81 | "png-chunk-text": "^1.0.0", | 81 | "png-chunk-text": "^1.0.0", |
| 82 | "png-chunks-extract": "^1.0.0", | 82 | "png-chunks-extract": "^1.0.0", |
| 83 | "proxy-agent": "^6.5.0", | 83 | "proxy-agent": "^6.5.0", |
| @@ -87,18 +87,18 @@ | |||
| 87 | "seedrandom": "^3.0.5", | 87 | "seedrandom": "^3.0.5", |
| 88 | "showdown": "^2.1.0", | 88 | "showdown": "^2.1.0", |
| 89 | "sillytavern-transformers": "2.14.6", | 89 | "sillytavern-transformers": "2.14.6", |
| 90 | "simple-git": "^3.27.0", | 90 | "simple-git": "^3.28.0", |
| 91 | "slidetoggle": "^4.0.0", | 91 | "slidetoggle": "^4.0.0", |
| 92 | "tiktoken": "^1.0.20", | 92 | "tiktoken": "^1.0.21", |
| 93 | "url-join": "^5.0.0", | 93 | "url-join": "^5.0.0", |
| 94 | "vectra": "^0.2.2", | 94 | "vectra": "^0.2.2", |
| 95 | "wavefile": "^11.0.0", | 95 | "wavefile": "^11.0.0", |
| 96 | "webpack": "^5.98.0", | 96 | "webpack": "^5.99.9", |
| 97 | "write-file-atomic": "^5.0.1", | 97 | "write-file-atomic": "^5.0.1", |
| 98 | "ws": "^8.18.1", | 98 | "ws": "^8.18.2", |
| 99 | "yaml": "^2.7.0", | 99 | "yaml": "^2.8.0", |
| 100 | "yargs": "^17.7.1", | 100 | "yargs": "^17.7.1", |
| 101 | "yauzl": "^2.10.0" | 101 | "yauzl": "^3.2.0" |
| 102 | }, | 102 | }, |
| 103 | "bin": { | 103 | "bin": { |
| 104 | "sillytavern": "server.js" | 104 | "sillytavern": "server.js" |
| @@ -107,24 +107,24 @@ | |||
| 107 | "@types/archiver": "^6.0.3", | 107 | "@types/archiver": "^6.0.3", |
| 108 | "@types/bytes": "^3.1.5", | 108 | "@types/bytes": "^3.1.5", |
| 109 | "@types/command-exists": "^1.2.3", | 109 | "@types/command-exists": "^1.2.3", |
| 110 | "@types/compression": "^1.7.5", | 110 | "@types/compression": "^1.8.1", |
| 111 | "@types/cookie-parser": "^1.4.8", | 111 | "@types/cookie-parser": "^1.4.9", |
| 112 | "@types/cookie-session": "^2.0.49", | 112 | "@types/cookie-session": "^2.0.49", |
| 113 | "@types/cors": "^2.8.17", | 113 | "@types/cors": "^2.8.19", |
| 114 | "@types/deno": "^2.2.0", | 114 | "@types/deno": "^2.3.0", |
| 115 | "@types/express": "^4.17.21", | 115 | "@types/express": "^4.17.23", |
| 116 | "@types/jquery": "^3.5.32", | 116 | "@types/jquery": "^3.5.32", |
| 117 | "@types/jquery-cropper": "^1.0.4", | 117 | "@types/jquery-cropper": "^1.0.4", |
| 118 | "@types/jquery.transit": "^0.9.33", | 118 | "@types/jquery.transit": "^0.9.33", |
| 119 | "@types/jqueryui": "^1.12.24", | 119 | "@types/jqueryui": "^1.12.24", |
| 120 | "@types/lodash": "^4.17.16", | 120 | "@types/lodash": "^4.17.17", |
| 121 | "@types/mime-types": "^2.1.4", | 121 | "@types/mime-types": "^3.0.1", |
| 122 | "@types/multer": "^1.4.12", | 122 | "@types/multer": "^1.4.13", |
| 123 | "@types/node": "^18.19.80", | 123 | "@types/node": "^18.19.84", |
| 124 | "@types/node-persist": "^3.1.8", | 124 | "@types/node-persist": "^3.1.8", |
| 125 | "@types/png-chunk-text": "^1.0.3", | 125 | "@types/png-chunk-text": "^1.0.3", |
| 126 | "@types/png-chunks-extract": "^1.0.2", | 126 | "@types/png-chunks-extract": "^1.0.2", |
| 127 | "@types/response-time": "^2.3.8", | 127 | "@types/response-time": "^2.3.9", |
| 128 | "@types/select2": "^4.0.63", | 128 | "@types/select2": "^4.0.63", |
| 129 | "@types/toastr": "^2.1.43", | 129 | "@types/toastr": "^2.1.43", |
| 130 | "@types/write-file-atomic": "^4.0.3", | 130 | "@types/write-file-atomic": "^4.0.3", |
| @@ -148,9 +148,9 @@ | |||
| 148 | } | 148 | } |
| 149 | }, | 149 | }, |
| 150 | "node_modules/@adobe/css-tools": { | 150 | "node_modules/@adobe/css-tools": { |
| 151 | "version": "4.4.2", | 151 | "version": "4.4.3", |
| 152 | "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz", | 152 | "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz", |
| 153 | "integrity": "sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==", | 153 | "integrity": "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==", |
| 154 | "license": "MIT" | 154 | "license": "MIT" |
| 155 | }, | 155 | }, |
| 156 | "node_modules/@agnai/sentencepiece-js": { | 156 | "node_modules/@agnai/sentencepiece-js": { |
| @@ -350,6 +350,7 @@ | |||
| 350 | "version": "8.0.2", | 350 | "version": "8.0.2", |
| 351 | "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", | 351 | "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", |
| 352 | "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", | 352 | "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", |
| 353 | "license": "ISC", | ||
| 353 | "dependencies": { | 354 | "dependencies": { |
| 354 | "string-width": "^5.1.2", | 355 | "string-width": "^5.1.2", |
| 355 | "string-width-cjs": "npm:string-width@^4.2.0", | 356 | "string-width-cjs": "npm:string-width@^4.2.0", |
| @@ -363,9 +364,10 @@ | |||
| 363 | } | 364 | } |
| 364 | }, | 365 | }, |
| 365 | "node_modules/@isaacs/cliui/node_modules/ansi-regex": { | 366 | "node_modules/@isaacs/cliui/node_modules/ansi-regex": { |
| 366 | "version": "6.0.1", | 367 | "version": "6.1.0", |
| 367 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", | 368 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", |
| 368 | "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", | 369 | "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", |
| 370 | "license": "MIT", | ||
| 369 | "engines": { | 371 | "engines": { |
| 370 | "node": ">=12" | 372 | "node": ">=12" |
| 371 | }, | 373 | }, |
| @@ -377,6 +379,7 @@ | |||
| 377 | "version": "6.2.1", | 379 | "version": "6.2.1", |
| 378 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", | 380 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", |
| 379 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", | 381 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", |
| 382 | "license": "MIT", | ||
| 380 | "engines": { | 383 | "engines": { |
| 381 | "node": ">=12" | 384 | "node": ">=12" |
| 382 | }, | 385 | }, |
| @@ -387,12 +390,14 @@ | |||
| 387 | "node_modules/@isaacs/cliui/node_modules/emoji-regex": { | 390 | "node_modules/@isaacs/cliui/node_modules/emoji-regex": { |
| 388 | "version": "9.2.2", | 391 | "version": "9.2.2", |
| 389 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", | 392 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", |
| 390 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" | 393 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", |
| 394 | "license": "MIT" | ||
| 391 | }, | 395 | }, |
| 392 | "node_modules/@isaacs/cliui/node_modules/string-width": { | 396 | "node_modules/@isaacs/cliui/node_modules/string-width": { |
| 393 | "version": "5.1.2", | 397 | "version": "5.1.2", |
| 394 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", | 398 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", |
| 395 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", | 399 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", |
| 400 | "license": "MIT", | ||
| 396 | "dependencies": { | 401 | "dependencies": { |
| 397 | "eastasianwidth": "^0.2.0", | 402 | "eastasianwidth": "^0.2.0", |
| 398 | "emoji-regex": "^9.2.2", | 403 | "emoji-regex": "^9.2.2", |
| @@ -409,6 +414,7 @@ | |||
| 409 | "version": "7.1.0", | 414 | "version": "7.1.0", |
| 410 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", | 415 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", |
| 411 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", | 416 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", |
| 417 | "license": "MIT", | ||
| 412 | "dependencies": { | 418 | "dependencies": { |
| 413 | "ansi-regex": "^6.0.1" | 419 | "ansi-regex": "^6.0.1" |
| 414 | }, | 420 | }, |
| @@ -423,6 +429,7 @@ | |||
| 423 | "version": "8.1.0", | 429 | "version": "8.1.0", |
| 424 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", | 430 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", |
| 425 | "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", | 431 | "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", |
| 432 | "license": "MIT", | ||
| 426 | "dependencies": { | 433 | "dependencies": { |
| 427 | "ansi-styles": "^6.1.0", | 434 | "ansi-styles": "^6.1.0", |
| 428 | "string-width": "^5.0.1", | 435 | "string-width": "^5.0.1", |
| @@ -1597,6 +1604,7 @@ | |||
| 1597 | "version": "0.11.0", | 1604 | "version": "0.11.0", |
| 1598 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", | 1605 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", |
| 1599 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", | 1606 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", |
| 1607 | "license": "MIT", | ||
| 1600 | "optional": true, | 1608 | "optional": true, |
| 1601 | "engines": { | 1609 | "engines": { |
| 1602 | "node": ">=14" | 1610 | "node": ">=14" |
| @@ -1779,13 +1787,14 @@ | |||
| 1779 | "license": "MIT" | 1787 | "license": "MIT" |
| 1780 | }, | 1788 | }, |
| 1781 | "node_modules/@types/compression": { | 1789 | "node_modules/@types/compression": { |
| 1782 | "version": "1.7.5", | 1790 | "version": "1.8.1", |
| 1783 | "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", | 1791 | "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.8.1.tgz", |
| 1784 | "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", | 1792 | "integrity": "sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==", |
| 1785 | "dev": true, | 1793 | "dev": true, |
| 1786 | "license": "MIT", | 1794 | "license": "MIT", |
| 1787 | "dependencies": { | 1795 | "dependencies": { |
| 1788 | "@types/express": "*" | 1796 | "@types/express": "*", |
| 1797 | "@types/node": "*" | ||
| 1789 | } | 1798 | } |
| 1790 | }, | 1799 | }, |
| 1791 | "node_modules/@types/connect": { | 1800 | "node_modules/@types/connect": { |
| @@ -1799,9 +1808,9 @@ | |||
| 1799 | } | 1808 | } |
| 1800 | }, | 1809 | }, |
| 1801 | "node_modules/@types/cookie-parser": { | 1810 | "node_modules/@types/cookie-parser": { |
| 1802 | "version": "1.4.8", | 1811 | "version": "1.4.9", |
| 1803 | "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.8.tgz", | 1812 | "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.9.tgz", |
| 1804 | "integrity": "sha512-l37JqFrOJ9yQfRQkljb41l0xVphc7kg5JTjjr+pLRZ0IyZ49V4BQ8vbF4Ut2C2e+WH4al3xD3ZwYwIUfnbT4NQ==", | 1813 | "integrity": "sha512-tGZiZ2Gtc4m3wIdLkZ8mkj1T6CEHb35+VApbL2T14Dew8HA7c+04dmKqsKRNC+8RJPm16JEK0tFSwdZqubfc4g==", |
| 1805 | "dev": true, | 1814 | "dev": true, |
| 1806 | "license": "MIT", | 1815 | "license": "MIT", |
| 1807 | "peerDependencies": { | 1816 | "peerDependencies": { |
| @@ -1820,9 +1829,9 @@ | |||
| 1820 | } | 1829 | } |
| 1821 | }, | 1830 | }, |
| 1822 | "node_modules/@types/cors": { | 1831 | "node_modules/@types/cors": { |
| 1823 | "version": "2.8.17", | 1832 | "version": "2.8.19", |
| 1824 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", | 1833 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", |
| 1825 | "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", | 1834 | "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", |
| 1826 | "dev": true, | 1835 | "dev": true, |
| 1827 | "license": "MIT", | 1836 | "license": "MIT", |
| 1828 | "dependencies": { | 1837 | "dependencies": { |
| @@ -1830,9 +1839,9 @@ | |||
| 1830 | } | 1839 | } |
| 1831 | }, | 1840 | }, |
| 1832 | "node_modules/@types/deno": { | 1841 | "node_modules/@types/deno": { |
| 1833 | "version": "2.2.0", | 1842 | "version": "2.3.0", |
| 1834 | "resolved": "https://registry.npmjs.org/@types/deno/-/deno-2.2.0.tgz", | 1843 | "resolved": "https://registry.npmjs.org/@types/deno/-/deno-2.3.0.tgz", |
| 1835 | "integrity": "sha512-4x6M/ZSyoQy6fJeMArP0dvvNT4IOolfySyukuqqKhsLmSXDV4wGanqXIZ+xFihw3TlReS6JTa4hRG9nAZInpmw==", | 1844 | "integrity": "sha512-/4SyefQpKjwNKGkq9qG3Ln7MazfbWKvydyVFBnXzP5OQA4u1paoFtaOe1iHKycIWHHkhYag0lPxyheThV1ijzw==", |
| 1836 | "dev": true, | 1845 | "dev": true, |
| 1837 | "license": "MIT" | 1846 | "license": "MIT" |
| 1838 | }, | 1847 | }, |
| @@ -1863,10 +1872,11 @@ | |||
| 1863 | "license": "MIT" | 1872 | "license": "MIT" |
| 1864 | }, | 1873 | }, |
| 1865 | "node_modules/@types/express": { | 1874 | "node_modules/@types/express": { |
| 1866 | "version": "4.17.21", | 1875 | "version": "4.17.23", |
| 1867 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", | 1876 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", |
| 1868 | "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", | 1877 | "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", |
| 1869 | "dev": true, | 1878 | "dev": true, |
| 1879 | "license": "MIT", | ||
| 1870 | "dependencies": { | 1880 | "dependencies": { |
| 1871 | "@types/body-parser": "*", | 1881 | "@types/body-parser": "*", |
| 1872 | "@types/express-serve-static-core": "^4.17.33", | 1882 | "@types/express-serve-static-core": "^4.17.33", |
| @@ -1962,9 +1972,9 @@ | |||
| 1962 | } | 1972 | } |
| 1963 | }, | 1973 | }, |
| 1964 | "node_modules/@types/lodash": { | 1974 | "node_modules/@types/lodash": { |
| 1965 | "version": "4.17.16", | 1975 | "version": "4.17.17", |
| 1966 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", | 1976 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz", |
| 1967 | "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==", | 1977 | "integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==", |
| 1968 | "dev": true, | 1978 | "dev": true, |
| 1969 | "license": "MIT" | 1979 | "license": "MIT" |
| 1970 | }, | 1980 | }, |
| @@ -1982,16 +1992,16 @@ | |||
| 1982 | "license": "MIT" | 1992 | "license": "MIT" |
| 1983 | }, | 1993 | }, |
| 1984 | "node_modules/@types/mime-types": { | 1994 | "node_modules/@types/mime-types": { |
| 1985 | "version": "2.1.4", | 1995 | "version": "3.0.1", |
| 1986 | "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", | 1996 | "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-3.0.1.tgz", |
| 1987 | "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", | 1997 | "integrity": "sha512-xRMsfuQbnRq1Ef+C+RKaENOxXX87Ygl38W1vDfPHRku02TgQr+Qd8iivLtAMcR0KF5/29xlnFihkTlbqFrGOVQ==", |
| 1988 | "dev": true, | 1998 | "dev": true, |
| 1989 | "license": "MIT" | 1999 | "license": "MIT" |
| 1990 | }, | 2000 | }, |
| 1991 | "node_modules/@types/multer": { | 2001 | "node_modules/@types/multer": { |
| 1992 | "version": "1.4.12", | 2002 | "version": "1.4.13", |
| 1993 | "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.12.tgz", | 2003 | "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.13.tgz", |
| 1994 | "integrity": "sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==", | 2004 | "integrity": "sha512-bhhdtPw7JqCiEfC9Jimx5LqX9BDIPJEh2q/fQ4bqbBPtyEZYr3cvF22NwG0DmPZNYA0CAf2CnqDB4KIGGpJcaw==", |
| 1995 | "dev": true, | 2005 | "dev": true, |
| 1996 | "license": "MIT", | 2006 | "license": "MIT", |
| 1997 | "dependencies": { | 2007 | "dependencies": { |
| @@ -1999,9 +2009,9 @@ | |||
| 1999 | } | 2009 | } |
| 2000 | }, | 2010 | }, |
| 2001 | "node_modules/@types/node": { | 2011 | "node_modules/@types/node": { |
| 2002 | "version": "18.19.80", | 2012 | "version": "18.19.84", |
| 2003 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.80.tgz", | 2013 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.84.tgz", |
| 2004 | "integrity": "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==", | 2014 | "integrity": "sha512-ACYy2HGcZPHxEeWTqowTF7dhXN+JU1o7Gr4b41klnn6pj2LD6rsiGqSZojMdk1Jh2ys3m76ap+ae1vvE4+5+vg==", |
| 2005 | "license": "MIT", | 2015 | "license": "MIT", |
| 2006 | "dependencies": { | 2016 | "dependencies": { |
| 2007 | "undici-types": "~5.26.4" | 2017 | "undici-types": "~5.26.4" |
| @@ -2064,9 +2074,9 @@ | |||
| 2064 | } | 2074 | } |
| 2065 | }, | 2075 | }, |
| 2066 | "node_modules/@types/response-time": { | 2076 | "node_modules/@types/response-time": { |
| 2067 | "version": "2.3.8", | 2077 | "version": "2.3.9", |
| 2068 | "resolved": "https://registry.npmjs.org/@types/response-time/-/response-time-2.3.8.tgz", | 2078 | "resolved": "https://registry.npmjs.org/@types/response-time/-/response-time-2.3.9.tgz", |
| 2069 | "integrity": "sha512-7qGaNYvdxc0zRab8oHpYx7AW17qj+G0xuag1eCrw3M2VWPJQ/HyKaaghWygiaOUl0y9x7QGQwppDpqLJ5V9pzw==", | 2079 | "integrity": "sha512-w5i5/y/1N3hkSBru1dat7Pf/YzdFLAANbKR78i2VIPnKw1Ub2ZNXE/n3K4v1BBMIIbAccgxpGZT8lIuLW284Dw==", |
| 2070 | "dev": true, | 2080 | "dev": true, |
| 2071 | "license": "MIT", | 2081 | "license": "MIT", |
| 2072 | "dependencies": { | 2082 | "dependencies": { |
| @@ -2378,6 +2388,18 @@ | |||
| 2378 | "node": ">= 0.6" | 2388 | "node": ">= 0.6" |
| 2379 | } | 2389 | } |
| 2380 | }, | 2390 | }, |
| 2391 | "node_modules/accepts/node_modules/mime-types": { | ||
| 2392 | "version": "2.1.35", | ||
| 2393 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", | ||
| 2394 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", | ||
| 2395 | "license": "MIT", | ||
| 2396 | "dependencies": { | ||
| 2397 | "mime-db": "1.52.0" | ||
| 2398 | }, | ||
| 2399 | "engines": { | ||
| 2400 | "node": ">= 0.6" | ||
| 2401 | } | ||
| 2402 | }, | ||
| 2381 | "node_modules/acorn": { | 2403 | "node_modules/acorn": { |
| 2382 | "version": "8.14.0", | 2404 | "version": "8.14.0", |
| 2383 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", | 2405 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", |
| @@ -2557,38 +2579,39 @@ | |||
| 2557 | } | 2579 | } |
| 2558 | }, | 2580 | }, |
| 2559 | "node_modules/archiver-utils/node_modules/brace-expansion": { | 2581 | "node_modules/archiver-utils/node_modules/brace-expansion": { |
| 2560 | "version": "2.0.1", | 2582 | "version": "2.0.2", |
| 2561 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", | 2583 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", |
| 2562 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", | 2584 | "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", |
| 2585 | "license": "MIT", | ||
| 2563 | "dependencies": { | 2586 | "dependencies": { |
| 2564 | "balanced-match": "^1.0.0" | 2587 | "balanced-match": "^1.0.0" |
| 2565 | } | 2588 | } |
| 2566 | }, | 2589 | }, |
| 2567 | "node_modules/archiver-utils/node_modules/glob": { | 2590 | "node_modules/archiver-utils/node_modules/glob": { |
| 2568 | "version": "10.3.12", | 2591 | "version": "10.4.5", |
| 2569 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", | 2592 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", |
| 2570 | "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", | 2593 | "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", |
| 2594 | "license": "ISC", | ||
| 2571 | "dependencies": { | 2595 | "dependencies": { |
| 2572 | "foreground-child": "^3.1.0", | 2596 | "foreground-child": "^3.1.0", |
| 2573 | "jackspeak": "^2.3.6", | 2597 | "jackspeak": "^3.1.2", |
| 2574 | "minimatch": "^9.0.1", | 2598 | "minimatch": "^9.0.4", |
| 2575 | "minipass": "^7.0.4", | 2599 | "minipass": "^7.1.2", |
| 2576 | "path-scurry": "^1.10.2" | 2600 | "package-json-from-dist": "^1.0.0", |
| 2601 | "path-scurry": "^1.11.1" | ||
| 2577 | }, | 2602 | }, |
| 2578 | "bin": { | 2603 | "bin": { |
| 2579 | "glob": "dist/esm/bin.mjs" | 2604 | "glob": "dist/esm/bin.mjs" |
| 2580 | }, | 2605 | }, |
| 2581 | "engines": { | ||
| 2582 | "node": ">=16 || 14 >=14.17" | ||
| 2583 | }, | ||
| 2584 | "funding": { | 2606 | "funding": { |
| 2585 | "url": "https://github.com/sponsors/isaacs" | 2607 | "url": "https://github.com/sponsors/isaacs" |
| 2586 | } | 2608 | } |
| 2587 | }, | 2609 | }, |
| 2588 | "node_modules/archiver-utils/node_modules/minimatch": { | 2610 | "node_modules/archiver-utils/node_modules/minimatch": { |
| 2589 | "version": "9.0.4", | 2611 | "version": "9.0.5", |
| 2590 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", | 2612 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", |
| 2591 | "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", | 2613 | "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", |
| 2614 | "license": "ISC", | ||
| 2592 | "dependencies": { | 2615 | "dependencies": { |
| 2593 | "brace-expansion": "^2.0.1" | 2616 | "brace-expansion": "^2.0.1" |
| 2594 | }, | 2617 | }, |
| @@ -2878,9 +2901,9 @@ | |||
| 2878 | "license": "MIT" | 2901 | "license": "MIT" |
| 2879 | }, | 2902 | }, |
| 2880 | "node_modules/brace-expansion": { | 2903 | "node_modules/brace-expansion": { |
| 2881 | "version": "1.1.11", | 2904 | "version": "1.1.12", |
| 2882 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", | 2905 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", |
| 2883 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", | 2906 | "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", |
| 2884 | "dev": true, | 2907 | "dev": true, |
| 2885 | "license": "MIT", | 2908 | "license": "MIT", |
| 2886 | "dependencies": { | 2909 | "dependencies": { |
| @@ -2968,6 +2991,21 @@ | |||
| 2968 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", | 2991 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", |
| 2969 | "license": "MIT" | 2992 | "license": "MIT" |
| 2970 | }, | 2993 | }, |
| 2994 | "node_modules/bundle-name": { | ||
| 2995 | "version": "4.1.0", | ||
| 2996 | "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", | ||
| 2997 | "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", | ||
| 2998 | "license": "MIT", | ||
| 2999 | "dependencies": { | ||
| 3000 | "run-applescript": "^7.0.0" | ||
| 3001 | }, | ||
| 3002 | "engines": { | ||
| 3003 | "node": ">=18" | ||
| 3004 | }, | ||
| 3005 | "funding": { | ||
| 3006 | "url": "https://github.com/sponsors/sindresorhus" | ||
| 3007 | } | ||
| 3008 | }, | ||
| 2971 | "node_modules/busboy": { | 3009 | "node_modules/busboy": { |
| 2972 | "version": "1.6.0", | 3010 | "version": "1.6.0", |
| 2973 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", | 3011 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", |
| @@ -3665,9 +3703,9 @@ | |||
| 3665 | } | 3703 | } |
| 3666 | }, | 3704 | }, |
| 3667 | "node_modules/csrf-sync": { | 3705 | "node_modules/csrf-sync": { |
| 3668 | "version": "4.0.3", | 3706 | "version": "4.2.1", |
| 3669 | "resolved": "https://registry.npmjs.org/csrf-sync/-/csrf-sync-4.0.3.tgz", | 3707 | "resolved": "https://registry.npmjs.org/csrf-sync/-/csrf-sync-4.2.1.tgz", |
| 3670 | "integrity": "sha512-wXzltBBzt/7imzDt6ZT7G/axQG7jo4Sm0uXDUzFY8hR59qhDHdjqpW2hojS4oAVIZDzwlMQloIVCTJoDDh0wwA==", | 3708 | "integrity": "sha512-+q9tlUSCi/kbwr1NYwn5+MeuNhwxz3wSv1yl42BgIWfIuErZ3HajRwzvZTkfiyIqt1PZT8lQSlffhSYjCneN7g==", |
| 3671 | "license": "ISC", | 3709 | "license": "ISC", |
| 3672 | "dependencies": { | 3710 | "dependencies": { |
| 3673 | "http-errors": "^2.0.0" | 3711 | "http-errors": "^2.0.0" |
| @@ -3741,6 +3779,34 @@ | |||
| 3741 | "dev": true, | 3779 | "dev": true, |
| 3742 | "license": "MIT" | 3780 | "license": "MIT" |
| 3743 | }, | 3781 | }, |
| 3782 | "node_modules/default-browser": { | ||
| 3783 | "version": "5.2.1", | ||
| 3784 | "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", | ||
| 3785 | "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", | ||
| 3786 | "license": "MIT", | ||
| 3787 | "dependencies": { | ||
| 3788 | "bundle-name": "^4.1.0", | ||
| 3789 | "default-browser-id": "^5.0.0" | ||
| 3790 | }, | ||
| 3791 | "engines": { | ||
| 3792 | "node": ">=18" | ||
| 3793 | }, | ||
| 3794 | "funding": { | ||
| 3795 | "url": "https://github.com/sponsors/sindresorhus" | ||
| 3796 | } | ||
| 3797 | }, | ||
| 3798 | "node_modules/default-browser-id": { | ||
| 3799 | "version": "5.0.0", | ||
| 3800 | "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", | ||
| 3801 | "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", | ||
| 3802 | "license": "MIT", | ||
| 3803 | "engines": { | ||
| 3804 | "node": ">=18" | ||
| 3805 | }, | ||
| 3806 | "funding": { | ||
| 3807 | "url": "https://github.com/sponsors/sindresorhus" | ||
| 3808 | } | ||
| 3809 | }, | ||
| 3744 | "node_modules/defer-to-connect": { | 3810 | "node_modules/defer-to-connect": { |
| 3745 | "version": "2.0.1", | 3811 | "version": "2.0.1", |
| 3746 | "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", | 3812 | "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", |
| @@ -3768,12 +3834,15 @@ | |||
| 3768 | } | 3834 | } |
| 3769 | }, | 3835 | }, |
| 3770 | "node_modules/define-lazy-prop": { | 3836 | "node_modules/define-lazy-prop": { |
| 3771 | "version": "2.0.0", | 3837 | "version": "3.0.0", |
| 3772 | "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", | 3838 | "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", |
| 3773 | "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", | 3839 | "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", |
| 3774 | "license": "MIT", | 3840 | "license": "MIT", |
| 3775 | "engines": { | 3841 | "engines": { |
| 3776 | "node": ">=8" | 3842 | "node": ">=12" |
| 3843 | }, | ||
| 3844 | "funding": { | ||
| 3845 | "url": "https://github.com/sponsors/sindresorhus" | ||
| 3777 | } | 3846 | } |
| 3778 | }, | 3847 | }, |
| 3779 | "node_modules/degenerator": { | 3848 | "node_modules/degenerator": { |
| @@ -3894,9 +3963,9 @@ | |||
| 3894 | } | 3963 | } |
| 3895 | }, | 3964 | }, |
| 3896 | "node_modules/dompurify": { | 3965 | "node_modules/dompurify": { |
| 3897 | "version": "3.2.4", | 3966 | "version": "3.2.6", |
| 3898 | "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz", | 3967 | "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz", |
| 3899 | "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", | 3968 | "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", |
| 3900 | "license": "(MPL-2.0 OR Apache-2.0)", | 3969 | "license": "(MPL-2.0 OR Apache-2.0)", |
| 3901 | "optionalDependencies": { | 3970 | "optionalDependencies": { |
| 3902 | "@types/trusted-types": "^2.0.7" | 3971 | "@types/trusted-types": "^2.0.7" |
| @@ -3953,7 +4022,8 @@ | |||
| 3953 | "node_modules/eastasianwidth": { | 4022 | "node_modules/eastasianwidth": { |
| 3954 | "version": "0.2.0", | 4023 | "version": "0.2.0", |
| 3955 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", | 4024 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", |
| 3956 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" | 4025 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", |
| 4026 | "license": "MIT" | ||
| 3957 | }, | 4027 | }, |
| 3958 | "node_modules/ee-first": { | 4028 | "node_modules/ee-first": { |
| 3959 | "version": "1.1.1", | 4029 | "version": "1.1.1", |
| @@ -4564,15 +4634,6 @@ | |||
| 4564 | "reusify": "^1.0.4" | 4634 | "reusify": "^1.0.4" |
| 4565 | } | 4635 | } |
| 4566 | }, | 4636 | }, |
| 4567 | "node_modules/fd-slicer": { | ||
| 4568 | "version": "1.1.0", | ||
| 4569 | "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", | ||
| 4570 | "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", | ||
| 4571 | "license": "MIT", | ||
| 4572 | "dependencies": { | ||
| 4573 | "pend": "~1.2.0" | ||
| 4574 | } | ||
| 4575 | }, | ||
| 4576 | "node_modules/fetch-blob": { | 4637 | "node_modules/fetch-blob": { |
| 4577 | "version": "3.2.0", | 4638 | "version": "3.2.0", |
| 4578 | "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", | 4639 | "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", |
| @@ -4724,14 +4785,15 @@ | |||
| 4724 | } | 4785 | } |
| 4725 | }, | 4786 | }, |
| 4726 | "node_modules/form-data": { | 4787 | "node_modules/form-data": { |
| 4727 | "version": "4.0.2", | 4788 | "version": "4.0.3", |
| 4728 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", | 4789 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", |
| 4729 | "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", | 4790 | "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", |
| 4730 | "license": "MIT", | 4791 | "license": "MIT", |
| 4731 | "dependencies": { | 4792 | "dependencies": { |
| 4732 | "asynckit": "^0.4.0", | 4793 | "asynckit": "^0.4.0", |
| 4733 | "combined-stream": "^1.0.8", | 4794 | "combined-stream": "^1.0.8", |
| 4734 | "es-set-tostringtag": "^2.1.0", | 4795 | "es-set-tostringtag": "^2.1.0", |
| 4796 | "hasown": "^2.0.2", | ||
| 4735 | "mime-types": "^2.1.12" | 4797 | "mime-types": "^2.1.12" |
| 4736 | }, | 4798 | }, |
| 4737 | "engines": { | 4799 | "engines": { |
| @@ -4744,6 +4806,18 @@ | |||
| 4744 | "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", | 4806 | "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", |
| 4745 | "license": "MIT" | 4807 | "license": "MIT" |
| 4746 | }, | 4808 | }, |
| 4809 | "node_modules/form-data/node_modules/mime-types": { | ||
| 4810 | "version": "2.1.35", | ||
| 4811 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", | ||
| 4812 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", | ||
| 4813 | "license": "MIT", | ||
| 4814 | "dependencies": { | ||
| 4815 | "mime-db": "1.52.0" | ||
| 4816 | }, | ||
| 4817 | "engines": { | ||
| 4818 | "node": ">= 0.6" | ||
| 4819 | } | ||
| 4820 | }, | ||
| 4747 | "node_modules/formdata-node": { | 4821 | "node_modules/formdata-node": { |
| 4748 | "version": "4.4.1", | 4822 | "version": "4.4.1", |
| 4749 | "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", | 4823 | "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", |
| @@ -5144,12 +5218,12 @@ | |||
| 5144 | } | 5218 | } |
| 5145 | }, | 5219 | }, |
| 5146 | "node_modules/helmet": { | 5220 | "node_modules/helmet": { |
| 5147 | "version": "7.2.0", | 5221 | "version": "8.1.0", |
| 5148 | "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz", | 5222 | "resolved": "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz", |
| 5149 | "integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==", | 5223 | "integrity": "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==", |
| 5150 | "license": "MIT", | 5224 | "license": "MIT", |
| 5151 | "engines": { | 5225 | "engines": { |
| 5152 | "node": ">=16.0.0" | 5226 | "node": ">=18.0.0" |
| 5153 | } | 5227 | } |
| 5154 | }, | 5228 | }, |
| 5155 | "node_modules/highlight.js": { | 5229 | "node_modules/highlight.js": { |
| @@ -5162,9 +5236,9 @@ | |||
| 5162 | } | 5236 | } |
| 5163 | }, | 5237 | }, |
| 5164 | "node_modules/html-entities": { | 5238 | "node_modules/html-entities": { |
| 5165 | "version": "2.5.2", | 5239 | "version": "2.6.0", |
| 5166 | "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", | 5240 | "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", |
| 5167 | "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", | 5241 | "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", |
| 5168 | "funding": [ | 5242 | "funding": [ |
| 5169 | { | 5243 | { |
| 5170 | "type": "github", | 5244 | "type": "github", |
| @@ -5517,6 +5591,24 @@ | |||
| 5517 | "node": ">=0.10.0" | 5591 | "node": ">=0.10.0" |
| 5518 | } | 5592 | } |
| 5519 | }, | 5593 | }, |
| 5594 | "node_modules/is-inside-container": { | ||
| 5595 | "version": "1.0.0", | ||
| 5596 | "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", | ||
| 5597 | "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", | ||
| 5598 | "license": "MIT", | ||
| 5599 | "dependencies": { | ||
| 5600 | "is-docker": "^3.0.0" | ||
| 5601 | }, | ||
| 5602 | "bin": { | ||
| 5603 | "is-inside-container": "cli.js" | ||
| 5604 | }, | ||
| 5605 | "engines": { | ||
| 5606 | "node": ">=14.16" | ||
| 5607 | }, | ||
| 5608 | "funding": { | ||
| 5609 | "url": "https://github.com/sponsors/sindresorhus" | ||
| 5610 | } | ||
| 5611 | }, | ||
| 5520 | "node_modules/is-path-inside": { | 5612 | "node_modules/is-path-inside": { |
| 5521 | "version": "3.0.3", | 5613 | "version": "3.0.3", |
| 5522 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", | 5614 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", |
| @@ -5539,27 +5631,15 @@ | |||
| 5539 | } | 5631 | } |
| 5540 | }, | 5632 | }, |
| 5541 | "node_modules/is-wsl": { | 5633 | "node_modules/is-wsl": { |
| 5542 | "version": "2.2.0", | 5634 | "version": "3.1.0", |
| 5543 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", | 5635 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", |
| 5544 | "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", | 5636 | "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", |
| 5545 | "license": "MIT", | 5637 | "license": "MIT", |
| 5546 | "dependencies": { | 5638 | "dependencies": { |
| 5547 | "is-docker": "^2.0.0" | 5639 | "is-inside-container": "^1.0.0" |
| 5548 | }, | 5640 | }, |
| 5549 | "engines": { | 5641 | "engines": { |
| 5550 | "node": ">=8" | 5642 | "node": ">=16" |
| 5551 | } | ||
| 5552 | }, | ||
| 5553 | "node_modules/is-wsl/node_modules/is-docker": { | ||
| 5554 | "version": "2.2.1", | ||
| 5555 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", | ||
| 5556 | "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", | ||
| 5557 | "license": "MIT", | ||
| 5558 | "bin": { | ||
| 5559 | "is-docker": "cli.js" | ||
| 5560 | }, | ||
| 5561 | "engines": { | ||
| 5562 | "node": ">=8" | ||
| 5563 | }, | 5643 | }, |
| 5564 | "funding": { | 5644 | "funding": { |
| 5565 | "url": "https://github.com/sponsors/sindresorhus" | 5645 | "url": "https://github.com/sponsors/sindresorhus" |
| @@ -5608,15 +5688,13 @@ | |||
| 5608 | } | 5688 | } |
| 5609 | }, | 5689 | }, |
| 5610 | "node_modules/jackspeak": { | 5690 | "node_modules/jackspeak": { |
| 5611 | "version": "2.3.6", | 5691 | "version": "3.4.3", |
| 5612 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", | 5692 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", |
| 5613 | "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", | 5693 | "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", |
| 5694 | "license": "BlueOak-1.0.0", | ||
| 5614 | "dependencies": { | 5695 | "dependencies": { |
| 5615 | "@isaacs/cliui": "^8.0.2" | 5696 | "@isaacs/cliui": "^8.0.2" |
| 5616 | }, | 5697 | }, |
| 5617 | "engines": { | ||
| 5618 | "node": ">=14" | ||
| 5619 | }, | ||
| 5620 | "funding": { | 5698 | "funding": { |
| 5621 | "url": "https://github.com/sponsors/isaacs" | 5699 | "url": "https://github.com/sponsors/isaacs" |
| 5622 | }, | 5700 | }, |
| @@ -5925,12 +6003,10 @@ | |||
| 5925 | } | 6003 | } |
| 5926 | }, | 6004 | }, |
| 5927 | "node_modules/lru-cache": { | 6005 | "node_modules/lru-cache": { |
| 5928 | "version": "10.2.0", | 6006 | "version": "10.4.3", |
| 5929 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", | 6007 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", |
| 5930 | "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", | 6008 | "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", |
| 5931 | "engines": { | 6009 | "license": "ISC" |
| 5932 | "node": "14 || >=16.14" | ||
| 5933 | } | ||
| 5934 | }, | 6010 | }, |
| 5935 | "node_modules/math-intrinsics": { | 6011 | "node_modules/math-intrinsics": { |
| 5936 | "version": "1.1.0", | 6012 | "version": "1.1.0", |
| @@ -6007,17 +6083,26 @@ | |||
| 6007 | } | 6083 | } |
| 6008 | }, | 6084 | }, |
| 6009 | "node_modules/mime-types": { | 6085 | "node_modules/mime-types": { |
| 6010 | "version": "2.1.35", | 6086 | "version": "3.0.1", |
| 6011 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", | 6087 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", |
| 6012 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", | 6088 | "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", |
| 6013 | "license": "MIT", | 6089 | "license": "MIT", |
| 6014 | "dependencies": { | 6090 | "dependencies": { |
| 6015 | "mime-db": "1.52.0" | 6091 | "mime-db": "^1.54.0" |
| 6016 | }, | 6092 | }, |
| 6017 | "engines": { | 6093 | "engines": { |
| 6018 | "node": ">= 0.6" | 6094 | "node": ">= 0.6" |
| 6019 | } | 6095 | } |
| 6020 | }, | 6096 | }, |
| 6097 | "node_modules/mime-types/node_modules/mime-db": { | ||
| 6098 | "version": "1.54.0", | ||
| 6099 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", | ||
| 6100 | "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", | ||
| 6101 | "license": "MIT", | ||
| 6102 | "engines": { | ||
| 6103 | "node": ">= 0.6" | ||
| 6104 | } | ||
| 6105 | }, | ||
| 6021 | "node_modules/mimic-response": { | 6106 | "node_modules/mimic-response": { |
| 6022 | "version": "3.1.0", | 6107 | "version": "3.1.0", |
| 6023 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", | 6108 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", |
| @@ -6061,9 +6146,10 @@ | |||
| 6061 | } | 6146 | } |
| 6062 | }, | 6147 | }, |
| 6063 | "node_modules/minipass": { | 6148 | "node_modules/minipass": { |
| 6064 | "version": "7.0.4", | 6149 | "version": "7.1.2", |
| 6065 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", | 6150 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", |
| 6066 | "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", | 6151 | "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", |
| 6152 | "license": "ISC", | ||
| 6067 | "engines": { | 6153 | "engines": { |
| 6068 | "node": ">=16 || 14 >=14.17" | 6154 | "node": ">=16 || 14 >=14.17" |
| 6069 | } | 6155 | } |
| @@ -6078,9 +6164,9 @@ | |||
| 6078 | } | 6164 | } |
| 6079 | }, | 6165 | }, |
| 6080 | "node_modules/morphdom": { | 6166 | "node_modules/morphdom": { |
| 6081 | "version": "2.7.4", | 6167 | "version": "2.7.5", |
| 6082 | "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.4.tgz", | 6168 | "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.5.tgz", |
| 6083 | "integrity": "sha512-ATTbWMgGa+FaMU3FhnFYB6WgulCqwf6opOll4CBzmVDTLvPMmUPrEv8CudmLPK0MESa64+6B89fWOxP3+YIlxQ==", | 6169 | "integrity": "sha512-z6bfWFMra7kBqDjQGHud1LSXtq5JJC060viEkQFMBX6baIecpkNr2Ywrn2OQfWP3rXiNFQRPoFjD8/TvJcWcDg==", |
| 6084 | "license": "MIT" | 6170 | "license": "MIT" |
| 6085 | }, | 6171 | }, |
| 6086 | "node_modules/ms": { | 6172 | "node_modules/ms": { |
| @@ -6333,32 +6419,18 @@ | |||
| 6333 | } | 6419 | } |
| 6334 | }, | 6420 | }, |
| 6335 | "node_modules/open": { | 6421 | "node_modules/open": { |
| 6336 | "version": "8.4.2", | 6422 | "version": "10.1.2", |
| 6337 | "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", | 6423 | "resolved": "https://registry.npmjs.org/open/-/open-10.1.2.tgz", |
| 6338 | "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", | 6424 | "integrity": "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==", |
| 6339 | "license": "MIT", | 6425 | "license": "MIT", |
| 6340 | "dependencies": { | 6426 | "dependencies": { |
| 6341 | "define-lazy-prop": "^2.0.0", | 6427 | "default-browser": "^5.2.1", |
| 6342 | "is-docker": "^2.1.1", | 6428 | "define-lazy-prop": "^3.0.0", |
| 6343 | "is-wsl": "^2.2.0" | 6429 | "is-inside-container": "^1.0.0", |
| 6344 | }, | 6430 | "is-wsl": "^3.1.0" |
| 6345 | "engines": { | ||
| 6346 | "node": ">=12" | ||
| 6347 | }, | ||
| 6348 | "funding": { | ||
| 6349 | "url": "https://github.com/sponsors/sindresorhus" | ||
| 6350 | } | ||
| 6351 | }, | ||
| 6352 | "node_modules/open/node_modules/is-docker": { | ||
| 6353 | "version": "2.2.1", | ||
| 6354 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", | ||
| 6355 | "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", | ||
| 6356 | "license": "MIT", | ||
| 6357 | "bin": { | ||
| 6358 | "is-docker": "cli.js" | ||
| 6359 | }, | 6431 | }, |
| 6360 | "engines": { | 6432 | "engines": { |
| 6361 | "node": ">=8" | 6433 | "node": ">=18" |
| 6362 | }, | 6434 | }, |
| 6363 | "funding": { | 6435 | "funding": { |
| 6364 | "url": "https://github.com/sponsors/sindresorhus" | 6436 | "url": "https://github.com/sponsors/sindresorhus" |
| @@ -6517,6 +6589,12 @@ | |||
| 6517 | "node": ">= 14" | 6589 | "node": ">= 14" |
| 6518 | } | 6590 | } |
| 6519 | }, | 6591 | }, |
| 6592 | "node_modules/package-json-from-dist": { | ||
| 6593 | "version": "1.0.1", | ||
| 6594 | "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", | ||
| 6595 | "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", | ||
| 6596 | "license": "BlueOak-1.0.0" | ||
| 6597 | }, | ||
| 6520 | "node_modules/pako": { | 6598 | "node_modules/pako": { |
| 6521 | "version": "1.0.11", | 6599 | "version": "1.0.11", |
| 6522 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", | 6600 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", |
| @@ -6642,15 +6720,16 @@ | |||
| 6642 | } | 6720 | } |
| 6643 | }, | 6721 | }, |
| 6644 | "node_modules/path-scurry": { | 6722 | "node_modules/path-scurry": { |
| 6645 | "version": "1.10.2", | 6723 | "version": "1.11.1", |
| 6646 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", | 6724 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", |
| 6647 | "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", | 6725 | "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", |
| 6726 | "license": "BlueOak-1.0.0", | ||
| 6648 | "dependencies": { | 6727 | "dependencies": { |
| 6649 | "lru-cache": "^10.2.0", | 6728 | "lru-cache": "^10.2.0", |
| 6650 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" | 6729 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" |
| 6651 | }, | 6730 | }, |
| 6652 | "engines": { | 6731 | "engines": { |
| 6653 | "node": ">=16 || 14 >=14.17" | 6732 | "node": ">=16 || 14 >=14.18" |
| 6654 | }, | 6733 | }, |
| 6655 | "funding": { | 6734 | "funding": { |
| 6656 | "url": "https://github.com/sponsors/isaacs" | 6735 | "url": "https://github.com/sponsors/isaacs" |
| @@ -7067,9 +7146,10 @@ | |||
| 7067 | } | 7146 | } |
| 7068 | }, | 7147 | }, |
| 7069 | "node_modules/readdir-glob/node_modules/brace-expansion": { | 7148 | "node_modules/readdir-glob/node_modules/brace-expansion": { |
| 7070 | "version": "2.0.1", | 7149 | "version": "2.0.2", |
| 7071 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", | 7150 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", |
| 7072 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", | 7151 | "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", |
| 7152 | "license": "MIT", | ||
| 7073 | "dependencies": { | 7153 | "dependencies": { |
| 7074 | "balanced-match": "^1.0.0" | 7154 | "balanced-match": "^1.0.0" |
| 7075 | } | 7155 | } |
| @@ -7177,6 +7257,18 @@ | |||
| 7177 | "url": "https://github.com/sponsors/isaacs" | 7257 | "url": "https://github.com/sponsors/isaacs" |
| 7178 | } | 7258 | } |
| 7179 | }, | 7259 | }, |
| 7260 | "node_modules/run-applescript": { | ||
| 7261 | "version": "7.0.0", | ||
| 7262 | "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", | ||
| 7263 | "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", | ||
| 7264 | "license": "MIT", | ||
| 7265 | "engines": { | ||
| 7266 | "node": ">=18" | ||
| 7267 | }, | ||
| 7268 | "funding": { | ||
| 7269 | "url": "https://github.com/sponsors/sindresorhus" | ||
| 7270 | } | ||
| 7271 | }, | ||
| 7180 | "node_modules/run-parallel": { | 7272 | "node_modules/run-parallel": { |
| 7181 | "version": "1.2.0", | 7273 | "version": "1.2.0", |
| 7182 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", | 7274 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", |
| @@ -7229,9 +7321,9 @@ | |||
| 7229 | "license": "ISC" | 7321 | "license": "ISC" |
| 7230 | }, | 7322 | }, |
| 7231 | "node_modules/schema-utils": { | 7323 | "node_modules/schema-utils": { |
| 7232 | "version": "4.3.0", | 7324 | "version": "4.3.2", |
| 7233 | "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", | 7325 | "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", |
| 7234 | "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", | 7326 | "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", |
| 7235 | "license": "MIT", | 7327 | "license": "MIT", |
| 7236 | "dependencies": { | 7328 | "dependencies": { |
| 7237 | "@types/json-schema": "^7.0.9", | 7329 | "@types/json-schema": "^7.0.9", |
| @@ -7503,14 +7595,14 @@ | |||
| 7503 | } | 7595 | } |
| 7504 | }, | 7596 | }, |
| 7505 | "node_modules/simple-git": { | 7597 | "node_modules/simple-git": { |
| 7506 | "version": "3.27.0", | 7598 | "version": "3.28.0", |
| 7507 | "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.27.0.tgz", | 7599 | "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.28.0.tgz", |
| 7508 | "integrity": "sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==", | 7600 | "integrity": "sha512-Rs/vQRwsn1ILH1oBUy8NucJlXmnnLeLCfcvbSehkPzbv3wwoFWIdtfd6Ndo6ZPhlPsCZ60CPI4rxurnwAa+a2w==", |
| 7509 | "license": "MIT", | 7601 | "license": "MIT", |
| 7510 | "dependencies": { | 7602 | "dependencies": { |
| 7511 | "@kwsites/file-exists": "^1.1.1", | 7603 | "@kwsites/file-exists": "^1.1.1", |
| 7512 | "@kwsites/promise-deferred": "^1.1.1", | 7604 | "@kwsites/promise-deferred": "^1.1.1", |
| 7513 | "debug": "^4.3.5" | 7605 | "debug": "^4.4.0" |
| 7514 | }, | 7606 | }, |
| 7515 | "funding": { | 7607 | "funding": { |
| 7516 | "type": "github", | 7608 | "type": "github", |
| @@ -7721,6 +7813,7 @@ | |||
| 7721 | "version": "4.2.3", | 7813 | "version": "4.2.3", |
| 7722 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", | 7814 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", |
| 7723 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", | 7815 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", |
| 7816 | "license": "MIT", | ||
| 7724 | "dependencies": { | 7817 | "dependencies": { |
| 7725 | "emoji-regex": "^8.0.0", | 7818 | "emoji-regex": "^8.0.0", |
| 7726 | "is-fullwidth-code-point": "^3.0.0", | 7819 | "is-fullwidth-code-point": "^3.0.0", |
| @@ -7747,6 +7840,7 @@ | |||
| 7747 | "version": "6.0.1", | 7840 | "version": "6.0.1", |
| 7748 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", | 7841 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", |
| 7749 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", | 7842 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", |
| 7843 | "license": "MIT", | ||
| 7750 | "dependencies": { | 7844 | "dependencies": { |
| 7751 | "ansi-regex": "^5.0.1" | 7845 | "ansi-regex": "^5.0.1" |
| 7752 | }, | 7846 | }, |
| @@ -7893,9 +7987,9 @@ | |||
| 7893 | "license": "MIT" | 7987 | "license": "MIT" |
| 7894 | }, | 7988 | }, |
| 7895 | "node_modules/tiktoken": { | 7989 | "node_modules/tiktoken": { |
| 7896 | "version": "1.0.20", | 7990 | "version": "1.0.21", |
| 7897 | "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.20.tgz", | 7991 | "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.21.tgz", |
| 7898 | "integrity": "sha512-zVIpXp84kth/Ni2me1uYlJgl2RZ2EjxwDaWLeDY/s6fZiyO9n1QoTOM5P7ZSYfToPvAvwYNMbg5LETVYVKyzfQ==", | 7992 | "integrity": "sha512-/kqtlepLMptX0OgbYD9aMYbM7EFrMZCL7EoHM8Psmg2FuhXoo/bH64KqOiZGGwa6oS9TPdSEDKBnV2LuB8+5vQ==", |
| 7899 | "license": "MIT" | 7993 | "license": "MIT" |
| 7900 | }, | 7994 | }, |
| 7901 | "node_modules/timm": { | 7995 | "node_modules/timm": { |
| @@ -8010,6 +8104,18 @@ | |||
| 8010 | "node": ">= 0.6" | 8104 | "node": ">= 0.6" |
| 8011 | } | 8105 | } |
| 8012 | }, | 8106 | }, |
| 8107 | "node_modules/type-is/node_modules/mime-types": { | ||
| 8108 | "version": "2.1.35", | ||
| 8109 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", | ||
| 8110 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", | ||
| 8111 | "license": "MIT", | ||
| 8112 | "dependencies": { | ||
| 8113 | "mime-db": "1.52.0" | ||
| 8114 | }, | ||
| 8115 | "engines": { | ||
| 8116 | "node": ">= 0.6" | ||
| 8117 | } | ||
| 8118 | }, | ||
| 8013 | "node_modules/typedarray": { | 8119 | "node_modules/typedarray": { |
| 8014 | "version": "0.0.6", | 8120 | "version": "0.0.6", |
| 8015 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", | 8121 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", |
| @@ -8213,13 +8319,14 @@ | |||
| 8213 | } | 8319 | } |
| 8214 | }, | 8320 | }, |
| 8215 | "node_modules/webpack": { | 8321 | "node_modules/webpack": { |
| 8216 | "version": "5.98.0", | 8322 | "version": "5.99.9", |
| 8217 | "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", | 8323 | "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz", |
| 8218 | "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", | 8324 | "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==", |
| 8219 | "license": "MIT", | 8325 | "license": "MIT", |
| 8220 | "dependencies": { | 8326 | "dependencies": { |
| 8221 | "@types/eslint-scope": "^3.7.7", | 8327 | "@types/eslint-scope": "^3.7.7", |
| 8222 | "@types/estree": "^1.0.6", | 8328 | "@types/estree": "^1.0.6", |
| 8329 | "@types/json-schema": "^7.0.15", | ||
| 8223 | "@webassemblyjs/ast": "^1.14.1", | 8330 | "@webassemblyjs/ast": "^1.14.1", |
| 8224 | "@webassemblyjs/wasm-edit": "^1.14.1", | 8331 | "@webassemblyjs/wasm-edit": "^1.14.1", |
| 8225 | "@webassemblyjs/wasm-parser": "^1.14.1", | 8332 | "@webassemblyjs/wasm-parser": "^1.14.1", |
| @@ -8236,7 +8343,7 @@ | |||
| 8236 | "loader-runner": "^4.2.0", | 8343 | "loader-runner": "^4.2.0", |
| 8237 | "mime-types": "^2.1.27", | 8344 | "mime-types": "^2.1.27", |
| 8238 | "neo-async": "^2.6.2", | 8345 | "neo-async": "^2.6.2", |
| 8239 | "schema-utils": "^4.3.0", | 8346 | "schema-utils": "^4.3.2", |
| 8240 | "tapable": "^2.1.1", | 8347 | "tapable": "^2.1.1", |
| 8241 | "terser-webpack-plugin": "^5.3.11", | 8348 | "terser-webpack-plugin": "^5.3.11", |
| 8242 | "watchpack": "^2.4.1", | 8349 | "watchpack": "^2.4.1", |
| @@ -8289,6 +8396,18 @@ | |||
| 8289 | "node": ">=4.0" | 8396 | "node": ">=4.0" |
| 8290 | } | 8397 | } |
| 8291 | }, | 8398 | }, |
| 8399 | "node_modules/webpack/node_modules/mime-types": { | ||
| 8400 | "version": "2.1.35", | ||
| 8401 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", | ||
| 8402 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", | ||
| 8403 | "license": "MIT", | ||
| 8404 | "dependencies": { | ||
| 8405 | "mime-db": "1.52.0" | ||
| 8406 | }, | ||
| 8407 | "engines": { | ||
| 8408 | "node": ">= 0.6" | ||
| 8409 | } | ||
| 8410 | }, | ||
| 8292 | "node_modules/whatwg-fetch": { | 8411 | "node_modules/whatwg-fetch": { |
| 8293 | "version": "3.6.20", | 8412 | "version": "3.6.20", |
| 8294 | "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", | 8413 | "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", |
| @@ -8351,6 +8470,7 @@ | |||
| 8351 | "version": "7.0.0", | 8470 | "version": "7.0.0", |
| 8352 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", | 8471 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", |
| 8353 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", | 8472 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", |
| 8473 | "license": "MIT", | ||
| 8354 | "dependencies": { | 8474 | "dependencies": { |
| 8355 | "ansi-styles": "^4.0.0", | 8475 | "ansi-styles": "^4.0.0", |
| 8356 | "string-width": "^4.1.0", | 8476 | "string-width": "^4.1.0", |
| @@ -8383,9 +8503,9 @@ | |||
| 8383 | } | 8503 | } |
| 8384 | }, | 8504 | }, |
| 8385 | "node_modules/ws": { | 8505 | "node_modules/ws": { |
| 8386 | "version": "8.18.1", | 8506 | "version": "8.18.2", |
| 8387 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", | 8507 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", |
| 8388 | "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", | 8508 | "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", |
| 8389 | "license": "MIT", | 8509 | "license": "MIT", |
| 8390 | "engines": { | 8510 | "engines": { |
| 8391 | "node": ">=10.0.0" | 8511 | "node": ">=10.0.0" |
| @@ -8462,15 +8582,15 @@ | |||
| 8462 | } | 8582 | } |
| 8463 | }, | 8583 | }, |
| 8464 | "node_modules/yaml": { | 8584 | "node_modules/yaml": { |
| 8465 | "version": "2.7.0", | 8585 | "version": "2.8.0", |
| 8466 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", | 8586 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", |
| 8467 | "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", | 8587 | "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", |
| 8468 | "license": "ISC", | 8588 | "license": "ISC", |
| 8469 | "bin": { | 8589 | "bin": { |
| 8470 | "yaml": "bin.mjs" | 8590 | "yaml": "bin.mjs" |
| 8471 | }, | 8591 | }, |
| 8472 | "engines": { | 8592 | "engines": { |
| 8473 | "node": ">= 14" | 8593 | "node": ">= 14.6" |
| 8474 | } | 8594 | } |
| 8475 | }, | 8595 | }, |
| 8476 | "node_modules/yargs": { | 8596 | "node_modules/yargs": { |
| @@ -8501,13 +8621,16 @@ | |||
| 8501 | } | 8621 | } |
| 8502 | }, | 8622 | }, |
| 8503 | "node_modules/yauzl": { | 8623 | "node_modules/yauzl": { |
| 8504 | "version": "2.10.0", | 8624 | "version": "3.2.0", |
| 8505 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", | 8625 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.2.0.tgz", |
| 8506 | "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", | 8626 | "integrity": "sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w==", |
| 8507 | "license": "MIT", | 8627 | "license": "MIT", |
| 8508 | "dependencies": { | 8628 | "dependencies": { |
| 8509 | "buffer-crc32": "~0.2.3", | 8629 | "buffer-crc32": "~0.2.3", |
| 8510 | "fd-slicer": "~1.1.0" | 8630 | "pend": "~1.2.0" |
| 8631 | }, | ||
| 8632 | "engines": { | ||
| 8633 | "node": ">=12" | ||
| 8511 | } | 8634 | } |
| 8512 | }, | 8635 | }, |
| 8513 | "node_modules/yocto-queue": { | 8636 | "node_modules/yocto-queue": { |
| @@ -1,6 +1,6 @@ | |||
| 1 | { | 1 | { |
| 2 | "dependencies": { | 2 | "dependencies": { |
| 3 | "@adobe/css-tools": "^4.4.2", | 3 | "@adobe/css-tools": "^4.4.3", |
| 4 | "@agnai/sentencepiece-js": "^1.1.1", | 4 | "@agnai/sentencepiece-js": "^1.1.1", |
| 5 | "@agnai/web-tokenizers": "^0.1.3", | 5 | "@agnai/web-tokenizers": "^0.1.3", |
| 6 | "@iconfu/svg-inject": "^1.2.3", | 6 | "@iconfu/svg-inject": "^1.2.3", |
| @@ -41,19 +41,19 @@ | |||
| 41 | "cookie-session": "^2.1.0", | 41 | "cookie-session": "^2.1.0", |
| 42 | "cors": "^2.8.5", | 42 | "cors": "^2.8.5", |
| 43 | "crc": "^4.3.2", | 43 | "crc": "^4.3.2", |
| 44 | "csrf-sync": "^4.0.3", | 44 | "csrf-sync": "^4.2.1", |
| 45 | "diff-match-patch": "^1.0.5", | 45 | "diff-match-patch": "^1.0.5", |
| 46 | "dompurify": "^3.2.4", | 46 | "dompurify": "^3.2.6", |
| 47 | "droll": "^0.2.1", | 47 | "droll": "^0.2.1", |
| 48 | "express": "^4.21.0", | 48 | "express": "^4.21.0", |
| 49 | "form-data": "^4.0.2", | 49 | "form-data": "^4.0.3", |
| 50 | "fuse.js": "^7.1.0", | 50 | "fuse.js": "^7.1.0", |
| 51 | "google-translate-api-browser": "^3.0.1", | 51 | "google-translate-api-browser": "^3.0.1", |
| 52 | "google-translate-api-x": "^10.7.2", | 52 | "google-translate-api-x": "^10.7.2", |
| 53 | "handlebars": "^4.7.8", | 53 | "handlebars": "^4.7.8", |
| 54 | "helmet": "^7.2.0", | 54 | "helmet": "^8.1.0", |
| 55 | "highlight.js": "^11.11.1", | 55 | "highlight.js": "^11.11.1", |
| 56 | "html-entities": "^2.5.2", | 56 | "html-entities": "^2.6.0", |
| 57 | "iconv-lite": "^0.6.3", | 57 | "iconv-lite": "^0.6.3", |
| 58 | "ip-matching": "^2.1.2", | 58 | "ip-matching": "^2.1.2", |
| 59 | "ip-regex": "^5.0.0", | 59 | "ip-regex": "^5.0.0", |
| @@ -61,13 +61,13 @@ | |||
| 61 | "is-docker": "^3.0.0", | 61 | "is-docker": "^3.0.0", |
| 62 | "localforage": "^1.10.0", | 62 | "localforage": "^1.10.0", |
| 63 | "lodash": "^4.17.21", | 63 | "lodash": "^4.17.21", |
| 64 | "mime-types": "^2.1.35", | 64 | "mime-types": "^3.0.1", |
| 65 | "moment": "^2.30.1", | 65 | "moment": "^2.30.1", |
| 66 | "morphdom": "^2.7.4", | 66 | "morphdom": "^2.7.5", |
| 67 | "multer": "^2.0.1", | 67 | "multer": "^2.0.1", |
| 68 | "node-fetch": "^3.3.2", | 68 | "node-fetch": "^3.3.2", |
| 69 | "node-persist": "^4.0.4", | 69 | "node-persist": "^4.0.4", |
| 70 | "open": "^8.4.2", | 70 | "open": "^10.1.2", |
| 71 | "png-chunk-text": "^1.0.0", | 71 | "png-chunk-text": "^1.0.0", |
| 72 | "png-chunks-extract": "^1.0.0", | 72 | "png-chunks-extract": "^1.0.0", |
| 73 | "proxy-agent": "^6.5.0", | 73 | "proxy-agent": "^6.5.0", |
| @@ -77,18 +77,18 @@ | |||
| 77 | "seedrandom": "^3.0.5", | 77 | "seedrandom": "^3.0.5", |
| 78 | "showdown": "^2.1.0", | 78 | "showdown": "^2.1.0", |
| 79 | "sillytavern-transformers": "2.14.6", | 79 | "sillytavern-transformers": "2.14.6", |
| 80 | "simple-git": "^3.27.0", | 80 | "simple-git": "^3.28.0", |
| 81 | "slidetoggle": "^4.0.0", | 81 | "slidetoggle": "^4.0.0", |
| 82 | "tiktoken": "^1.0.20", | 82 | "tiktoken": "^1.0.21", |
| 83 | "url-join": "^5.0.0", | 83 | "url-join": "^5.0.0", |
| 84 | "vectra": "^0.2.2", | 84 | "vectra": "^0.2.2", |
| 85 | "wavefile": "^11.0.0", | 85 | "wavefile": "^11.0.0", |
| 86 | "webpack": "^5.98.0", | 86 | "webpack": "^5.99.9", |
| 87 | "write-file-atomic": "^5.0.1", | 87 | "write-file-atomic": "^5.0.1", |
| 88 | "ws": "^8.18.1", | 88 | "ws": "^8.18.2", |
| 89 | "yaml": "^2.7.0", | 89 | "yaml": "^2.8.0", |
| 90 | "yargs": "^17.7.1", | 90 | "yargs": "^17.7.1", |
| 91 | "yauzl": "^2.10.0" | 91 | "yauzl": "^3.2.0" |
| 92 | }, | 92 | }, |
| 93 | "engines": { | 93 | "engines": { |
| 94 | "node": ">= 18" | 94 | "node": ">= 18" |
| @@ -111,7 +111,7 @@ | |||
| 111 | "type": "git", | 111 | "type": "git", |
| 112 | "url": "https://github.com/SillyTavern/SillyTavern.git" | 112 | "url": "https://github.com/SillyTavern/SillyTavern.git" |
| 113 | }, | 113 | }, |
| 114 | "version": "1.13.0", | 114 | "version": "1.13.1", |
| 115 | "scripts": { | 115 | "scripts": { |
| 116 | "start": "node server.js", | 116 | "start": "node server.js", |
| 117 | "debug": "node --inspect server.js", | 117 | "debug": "node --inspect server.js", |
| @@ -137,24 +137,24 @@ | |||
| 137 | "@types/archiver": "^6.0.3", | 137 | "@types/archiver": "^6.0.3", |
| 138 | "@types/bytes": "^3.1.5", | 138 | "@types/bytes": "^3.1.5", |
| 139 | "@types/command-exists": "^1.2.3", | 139 | "@types/command-exists": "^1.2.3", |
| 140 | "@types/compression": "^1.7.5", | 140 | "@types/compression": "^1.8.1", |
| 141 | "@types/cookie-parser": "^1.4.8", | 141 | "@types/cookie-parser": "^1.4.9", |
| 142 | "@types/cookie-session": "^2.0.49", | 142 | "@types/cookie-session": "^2.0.49", |
| 143 | "@types/cors": "^2.8.17", | 143 | "@types/cors": "^2.8.19", |
| 144 | "@types/deno": "^2.2.0", | 144 | "@types/deno": "^2.3.0", |
| 145 | "@types/express": "^4.17.21", | 145 | "@types/express": "^4.17.23", |
| 146 | "@types/jquery": "^3.5.32", | 146 | "@types/jquery": "^3.5.32", |
| 147 | "@types/jquery-cropper": "^1.0.4", | 147 | "@types/jquery-cropper": "^1.0.4", |
| 148 | "@types/jquery.transit": "^0.9.33", | 148 | "@types/jquery.transit": "^0.9.33", |
| 149 | "@types/jqueryui": "^1.12.24", | 149 | "@types/jqueryui": "^1.12.24", |
| 150 | "@types/lodash": "^4.17.16", | 150 | "@types/lodash": "^4.17.17", |
| 151 | "@types/mime-types": "^2.1.4", | 151 | "@types/mime-types": "^3.0.1", |
| 152 | "@types/multer": "^1.4.12", | 152 | "@types/multer": "^1.4.13", |
| 153 | "@types/node": "^18.19.80", | 153 | "@types/node": "^18.19.84", |
| 154 | "@types/node-persist": "^3.1.8", | 154 | "@types/node-persist": "^3.1.8", |
| 155 | "@types/png-chunk-text": "^1.0.3", | 155 | "@types/png-chunk-text": "^1.0.3", |
| 156 | "@types/png-chunks-extract": "^1.0.2", | 156 | "@types/png-chunks-extract": "^1.0.2", |
| 157 | "@types/response-time": "^2.3.8", | 157 | "@types/response-time": "^2.3.9", |
| 158 | "@types/select2": "^4.0.63", | 158 | "@types/select2": "^4.0.63", |
| 159 | "@types/toastr": "^2.1.43", | 159 | "@types/toastr": "^2.1.43", |
| 160 | "@types/write-file-atomic": "^4.0.3", | 160 | "@types/write-file-atomic": "^4.0.3", |
| @@ -55,6 +55,7 @@ | |||
| 55 | 55 | ||
| 56 | /* Flashing for highlighting animation */ | 56 | /* Flashing for highlighting animation */ |
| 57 | @keyframes flash { | 57 | @keyframes flash { |
| 58 | |||
| 58 | 0%, | 59 | 0%, |
| 59 | 50%, | 60 | 50%, |
| 60 | 100% { | 61 | 100% { |
| @@ -122,3 +123,12 @@ | |||
| 122 | border-top-color: var(--progFlashColor); | 123 | border-top-color: var(--progFlashColor); |
| 123 | } | 124 | } |
| 124 | } | 125 | } |
| 126 | |||
| 127 | /* Scroll delay animations */ | ||
| 128 | @keyframes hide-scroll { | ||
| 129 | |||
| 130 | from, | ||
| 131 | to { | ||
| 132 | overflow-y: hidden; | ||
| 133 | } | ||
| 134 | } | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | #rm_print_characters_block.group_overlay_mode_select .character_select { | 1 | #rm_print_characters_block.group_overlay_mode_select .character_select { |
| 2 | transition: background-color 0.4s ease; | 2 | transition: background-color var(--animation-duration-3x) ease; |
| 3 | background-color: rgba(170, 170, 170, 0.15); | 3 | background-color: rgba(170, 170, 170, 0.15); |
| 4 | } | 4 | } |
| 5 | 5 | ||
| @@ -0,0 +1,149 @@ | |||
| 1 | .dataMaidDialogContainer { | ||
| 2 | height: 100%; | ||
| 3 | overflow: hidden; | ||
| 4 | } | ||
| 5 | |||
| 6 | .dataMaidDialog { | ||
| 7 | display: flex; | ||
| 8 | flex-direction: column; | ||
| 9 | gap: 5px; | ||
| 10 | height: 100%; | ||
| 11 | overflow: hidden; | ||
| 12 | } | ||
| 13 | |||
| 14 | .dataMaidDialogHeader { | ||
| 15 | display: flex; | ||
| 16 | gap: 10px; | ||
| 17 | align-items: center; | ||
| 18 | text-align: left; | ||
| 19 | } | ||
| 20 | |||
| 21 | .dataMaidHeaderInfo { | ||
| 22 | flex: 1; | ||
| 23 | margin: 0; | ||
| 24 | padding: 5px 10px; | ||
| 25 | } | ||
| 26 | |||
| 27 | .dataMaidTextView { | ||
| 28 | width: 100%; | ||
| 29 | height: 100%; | ||
| 30 | font-family: var(--monoFontFamily); | ||
| 31 | resize: none; | ||
| 32 | font-size: 0.95em; | ||
| 33 | } | ||
| 34 | |||
| 35 | .dataMaidImageView { | ||
| 36 | width: 100%; | ||
| 37 | height: 100%; | ||
| 38 | object-fit: contain; | ||
| 39 | } | ||
| 40 | |||
| 41 | .dataMaidSpinner { | ||
| 42 | display: flex; | ||
| 43 | justify-content: center; | ||
| 44 | align-items: center; | ||
| 45 | height: 100%; | ||
| 46 | } | ||
| 47 | |||
| 48 | .dataMaidPlaceholder { | ||
| 49 | display: flex; | ||
| 50 | justify-content: center; | ||
| 51 | align-items: center; | ||
| 52 | font-size: 1.05em; | ||
| 53 | } | ||
| 54 | |||
| 55 | .dataMaidResultsList:empty { | ||
| 56 | display: none; | ||
| 57 | } | ||
| 58 | |||
| 59 | .dataMaidResultsList { | ||
| 60 | text-align: left; | ||
| 61 | display: flex; | ||
| 62 | flex-direction: column; | ||
| 63 | gap: 2px; | ||
| 64 | overflow-y: auto; | ||
| 65 | height: 100%; | ||
| 66 | flex-grow: 1; | ||
| 67 | } | ||
| 68 | |||
| 69 | .dataMaidCategory { | ||
| 70 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 71 | border-radius: 10px; | ||
| 72 | padding: 0 10px; | ||
| 73 | } | ||
| 74 | |||
| 75 | .dataMaidCategoryHeader { | ||
| 76 | width: 100%; | ||
| 77 | display: flex; | ||
| 78 | align-items: center; | ||
| 79 | justify-content: space-between; | ||
| 80 | margin-right: 5px; | ||
| 81 | padding: 0 5px; | ||
| 82 | } | ||
| 83 | |||
| 84 | .dataMaidCategoryDetails { | ||
| 85 | display: flex; | ||
| 86 | flex-direction: column; | ||
| 87 | gap: 1px; | ||
| 88 | } | ||
| 89 | |||
| 90 | .dataMaidCategoryName { | ||
| 91 | flex: 3; | ||
| 92 | font-weight: bold; | ||
| 93 | font-size: 1.1em; | ||
| 94 | } | ||
| 95 | |||
| 96 | .dataMaidCategoryInfo { | ||
| 97 | flex: 1; | ||
| 98 | display: flex; | ||
| 99 | align-items: baseline; | ||
| 100 | gap: 5px; | ||
| 101 | } | ||
| 102 | |||
| 103 | .dataMaidCategoryContent { | ||
| 104 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 105 | padding: 5px; | ||
| 106 | border-radius: 10px; | ||
| 107 | background-color: var(--black30a); | ||
| 108 | margin: 10px 0; | ||
| 109 | } | ||
| 110 | |||
| 111 | .dataMaidCategoryContent>.info-block { | ||
| 112 | white-space: pre-wrap; | ||
| 113 | } | ||
| 114 | |||
| 115 | .dataMaidItem { | ||
| 116 | display: flex; | ||
| 117 | flex-direction: column; | ||
| 118 | padding: 5px; | ||
| 119 | width: 100%; | ||
| 120 | border-bottom: 1px solid var(--SmartThemeBorderColor); | ||
| 121 | } | ||
| 122 | |||
| 123 | .dataMaidItem:last-child { | ||
| 124 | border-bottom: none; | ||
| 125 | } | ||
| 126 | |||
| 127 | .dataMaidItemHeader { | ||
| 128 | display: flex; | ||
| 129 | align-items: center; | ||
| 130 | gap: 5px; | ||
| 131 | } | ||
| 132 | |||
| 133 | .dataMaidItemName { | ||
| 134 | display: flex; | ||
| 135 | flex: 1; | ||
| 136 | align-items: baseline; | ||
| 137 | gap: 2px; | ||
| 138 | word-break: break-all; | ||
| 139 | } | ||
| 140 | |||
| 141 | .dataMaidItemActions { | ||
| 142 | display: flex; | ||
| 143 | align-items: center; | ||
| 144 | gap: 5px; | ||
| 145 | } | ||
| 146 | |||
| 147 | .dataMaidItemActions>button { | ||
| 148 | font-size: 0.9em; | ||
| 149 | } | ||
| @@ -18,7 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | #load-spinner { | 19 | #load-spinner { |
| 20 | --spinner-size: 2em; | 20 | --spinner-size: 2em; |
| 21 | transition: all 300ms ease-out; | 21 | transition: all var(--animation-duration-2x) ease-out; |
| 22 | opacity: 1; | 22 | opacity: 1; |
| 23 | top: calc(50% - var(--spinner-size) / 2); | 23 | top: calc(50% - var(--spinner-size) / 2); |
| 24 | left: calc(50% - var(--spinner-size) / 2); | 24 | left: calc(50% - var(--spinner-size) / 2); |
| @@ -23,7 +23,7 @@ body.login .userSelect { | |||
| 23 | width: 30%; | 23 | width: 30%; |
| 24 | cursor: pointer; | 24 | cursor: pointer; |
| 25 | margin: 5px 0; | 25 | margin: 5px 0; |
| 26 | transition: background-color 0.15s ease-in-out; | 26 | transition: background-color var(--animation-duration) ease-in-out; |
| 27 | display: flex; | 27 | display: flex; |
| 28 | align-items: center; | 28 | align-items: center; |
| 29 | justify-content: center; | 29 | justify-content: center; |
| @@ -43,7 +43,7 @@ | |||
| 43 | height: 25px; | 43 | height: 25px; |
| 44 | margin-left: 5px; | 44 | margin-left: 5px; |
| 45 | opacity: 0.5; | 45 | opacity: 0.5; |
| 46 | transition: all 250ms; | 46 | transition: all var(--animation-duration-2x); |
| 47 | position: unset !important; | 47 | position: unset !important; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| @@ -25,10 +25,6 @@ | |||
| 25 | font-size: 15px; | 25 | font-size: 15px; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | .mes_text img { | ||
| 29 | width: 100%; | ||
| 30 | } | ||
| 31 | |||
| 32 | #extensions_settings, | 28 | #extensions_settings, |
| 33 | #extensions_settings2 { | 29 | #extensions_settings2 { |
| 34 | width: 100% !important; | 30 | width: 100% !important; |
| @@ -241,6 +237,15 @@ | |||
| 241 | top: var(--topBarBlockSize) !important; | 237 | top: var(--topBarBlockSize) !important; |
| 242 | left: 0 !important; | 238 | left: 0 !important; |
| 243 | backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2)); | 239 | backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2)); |
| 240 | |||
| 241 | @starting-style { | ||
| 242 | height: 0; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | #left-nav-panel:not(.openDrawer), | ||
| 247 | #right-nav-panel:not(.openDrawer) { | ||
| 248 | height: 0; | ||
| 244 | } | 249 | } |
| 245 | 250 | ||
| 246 | /* | 251 | /* |
| @@ -79,7 +79,7 @@ | |||
| 79 | justify-content: center; | 79 | justify-content: center; |
| 80 | margin-left: 0.25em; | 80 | margin-left: 0.25em; |
| 81 | cursor: pointer; | 81 | cursor: pointer; |
| 82 | transition: 0.3s ease-in-out; | 82 | transition: var(--animation-duration-2x) ease-in-out; |
| 83 | height: 20px; | 83 | height: 20px; |
| 84 | width: 20px; | 84 | width: 20px; |
| 85 | filter: drop-shadow(0px 0px 2px black); | 85 | filter: drop-shadow(0px 0px 2px black); |
| @@ -239,7 +239,7 @@ | |||
| 239 | flex-direction: column; | 239 | flex-direction: column; |
| 240 | justify-content: center; | 240 | justify-content: center; |
| 241 | margin-left: 0.25em; | 241 | margin-left: 0.25em; |
| 242 | transition: 0.3s ease-in-out; | 242 | transition: var(--animation-duration-2x) ease-in-out; |
| 243 | filter: drop-shadow(0px 0px 2px black); | 243 | filter: drop-shadow(0px 0px 2px black); |
| 244 | } | 244 | } |
| 245 | 245 | ||
| @@ -172,7 +172,7 @@ | |||
| 172 | #rm_group_members .group_member:not(.disabled) .right_menu_button[data-action="disable"] { | 172 | #rm_group_members .group_member:not(.disabled) .right_menu_button[data-action="disable"] { |
| 173 | opacity: 0.4; | 173 | opacity: 0.4; |
| 174 | filter: brightness(0.5); | 174 | filter: brightness(0.5); |
| 175 | transition: all 0.2s ease-in-out; | 175 | transition: all var(--animation-duration-2x) ease-in-out; |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | /* #rm_group_members .right_menu_button[data-action="speak"]:hover, */ | 178 | /* #rm_group_members .right_menu_button[data-action="speak"]:hover, */ |
| @@ -0,0 +1,102 @@ | |||
| 1 | .secretKeyManager { | ||
| 2 | display: flex; | ||
| 3 | flex-direction: column; | ||
| 4 | gap: 5px; | ||
| 5 | height: 100%; | ||
| 6 | } | ||
| 7 | |||
| 8 | .secretKeyManagerHeader { | ||
| 9 | display: flex; | ||
| 10 | flex-direction: column; | ||
| 11 | justify-content: center; | ||
| 12 | align-items: center; | ||
| 13 | gap: 5px; | ||
| 14 | } | ||
| 15 | |||
| 16 | .secretKeyManagerSubtitle { | ||
| 17 | display: flex; | ||
| 18 | flex-direction: row; | ||
| 19 | justify-content: space-between; | ||
| 20 | align-items: center; | ||
| 21 | width: 100%; | ||
| 22 | } | ||
| 23 | |||
| 24 | .secretKeyManagerInfo { | ||
| 25 | display: flex; | ||
| 26 | flex-direction: column; | ||
| 27 | align-items: baseline; | ||
| 28 | flex: 1; | ||
| 29 | font-size: 0.95em; | ||
| 30 | } | ||
| 31 | |||
| 32 | .secretKeyManagerList { | ||
| 33 | display: flex; | ||
| 34 | flex-direction: column; | ||
| 35 | text-align: left; | ||
| 36 | gap: 5px; | ||
| 37 | flex: 1; | ||
| 38 | overflow-y: auto; | ||
| 39 | height: 100%; | ||
| 40 | } | ||
| 41 | |||
| 42 | .secretKeyManagerItem { | ||
| 43 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 44 | padding: 5px 10px; | ||
| 45 | border-radius: 10px; | ||
| 46 | background-color: var(--black30a); | ||
| 47 | display: flex; | ||
| 48 | flex-direction: row; | ||
| 49 | align-items: center; | ||
| 50 | } | ||
| 51 | |||
| 52 | .secretKeyManagerItem.active { | ||
| 53 | background-color: var(--cobalt30a); | ||
| 54 | } | ||
| 55 | |||
| 56 | .secretKeyManagerItemInfo { | ||
| 57 | display: flex; | ||
| 58 | flex-direction: column; | ||
| 59 | flex: 1; | ||
| 60 | gap: 5px; | ||
| 61 | } | ||
| 62 | |||
| 63 | .secretKeyManagerItemSubtitle, | ||
| 64 | .secretKeyManagerItemHeader { | ||
| 65 | word-break: break-all; | ||
| 66 | } | ||
| 67 | |||
| 68 | .secretKeyManagerItemId { | ||
| 69 | text-decoration: underline; | ||
| 70 | text-decoration-style: dotted; | ||
| 71 | cursor: pointer; | ||
| 72 | } | ||
| 73 | |||
| 74 | .secretKeyManagerItemActions { | ||
| 75 | display: flex; | ||
| 76 | flex-direction: column; | ||
| 77 | gap: 5px; | ||
| 78 | } | ||
| 79 | |||
| 80 | .secretKeyManagerItemActionsRow { | ||
| 81 | display: flex; | ||
| 82 | flex-direction: row; | ||
| 83 | gap: 5px; | ||
| 84 | } | ||
| 85 | |||
| 86 | .secretKeyManagerItemActionsRow>button { | ||
| 87 | margin: 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | .secretKeyManagerList:empty { | ||
| 91 | display: none; | ||
| 92 | } | ||
| 93 | |||
| 94 | .secretKeyManagerListEmpty { | ||
| 95 | display: flex; | ||
| 96 | justify-content: center; | ||
| 97 | align-items: center; | ||
| 98 | width: 100%; | ||
| 99 | opacity: 0.8; | ||
| 100 | font-weight: bold; | ||
| 101 | font-size: 1.05em; | ||
| 102 | } | ||
| @@ -125,7 +125,7 @@ | |||
| 125 | background-color: unset; | 125 | background-color: unset; |
| 126 | color: var(--SmartThemeBodyColor); | 126 | color: var(--SmartThemeBodyColor); |
| 127 | opacity: 0.5; | 127 | opacity: 0.5; |
| 128 | transition: opacity 200ms ease-in-out; | 128 | transition: opacity var(--animation-duration-2x) ease-in-out; |
| 129 | position: relative; | 129 | position: relative; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| @@ -203,7 +203,7 @@ | |||
| 203 | /* Styling for choice remove icon */ | 203 | /* Styling for choice remove icon */ |
| 204 | span.select2.select2-container .select2-selection__choice__remove { | 204 | span.select2.select2-container .select2-selection__choice__remove { |
| 205 | cursor: pointer; | 205 | cursor: pointer; |
| 206 | transition: background-color 0.3s; | 206 | transition: background-color var(--animation-duration-2x); |
| 207 | color: var(--SmartThemeBodyColor); | 207 | color: var(--SmartThemeBodyColor); |
| 208 | background-color: var(--black50a); | 208 | background-color: var(--black50a); |
| 209 | } | 209 | } |
| @@ -220,7 +220,7 @@ span.select2.select2-container .select2-selection__choice__remove:hover { | |||
| 220 | 220 | ||
| 221 | .select2_choice_clickable_buttonstyle+span.select2-container .select2-selection__choice__display { | 221 | .select2_choice_clickable_buttonstyle+span.select2-container .select2-selection__choice__display { |
| 222 | cursor: pointer; | 222 | cursor: pointer; |
| 223 | transition: background-color 0.3s; | 223 | transition: background-color var(--animation-duration-2x); |
| 224 | color: var(--SmartThemeBodyColor); | 224 | color: var(--SmartThemeBodyColor); |
| 225 | background-color: var(--black50a); | 225 | background-color: var(--black50a); |
| 226 | white-space: break-spaces; | 226 | white-space: break-spaces; |
| @@ -332,6 +332,10 @@ | |||
| 332 | overflow: hidden; | 332 | overflow: hidden; |
| 333 | } | 333 | } |
| 334 | 334 | ||
| 335 | .overflowYScroll { | ||
| 336 | overflow-y: scroll; | ||
| 337 | } | ||
| 338 | |||
| 335 | .padding0 { | 339 | .padding0 { |
| 336 | padding: 0; | 340 | padding: 0; |
| 337 | } | 341 | } |
| @@ -480,7 +484,7 @@ | |||
| 480 | } | 484 | } |
| 481 | 485 | ||
| 482 | .hoverglow { | 486 | .hoverglow { |
| 483 | transition: opacity 200ms; | 487 | transition: opacity var(--animation-duration-2x); |
| 484 | } | 488 | } |
| 485 | 489 | ||
| 486 | .hoverglow:hover { | 490 | .hoverglow:hover { |
| @@ -556,6 +560,10 @@ textarea:disabled { | |||
| 556 | min-width: fit-content; | 560 | min-width: fit-content; |
| 557 | } | 561 | } |
| 558 | 562 | ||
| 563 | .flexGap2 { | ||
| 564 | gap: 2px; | ||
| 565 | } | ||
| 566 | |||
| 559 | .flexGap5 { | 567 | .flexGap5 { |
| 560 | gap: 5px; | 568 | gap: 5px; |
| 561 | } | 569 | } |
| @@ -167,7 +167,7 @@ | |||
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | .rm_tag_filter .tag.actionable { | 169 | .rm_tag_filter .tag.actionable { |
| 170 | transition: opacity 200ms; | 170 | transition: opacity var(--animation-duration-2x); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | .rm_tag_filter .tag:hover { | 173 | .rm_tag_filter .tag:hover { |
| @@ -19,6 +19,7 @@ body:not(.tts) #ttsExtensionNarrateAll { | |||
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | body.no-hotswap .hotswap, | 21 | body.no-hotswap .hotswap, |
| 22 | body.no-hotswap .hotswap~hr, | ||
| 22 | body.no-timer .mes_timer, | 23 | body.no-timer .mes_timer, |
| 23 | body.no-timestamps .timestamp, | 24 | body.no-timestamps .timestamp, |
| 24 | body.no-tokenCount .tokenCounterDisplay, | 25 | body.no-tokenCount .tokenCounterDisplay, |
| @@ -28,6 +29,12 @@ body.hideChatAvatars .mesAvatarWrapper .avatar { | |||
| 28 | display: none !important; | 29 | display: none !important; |
| 29 | } | 30 | } |
| 30 | 31 | ||
| 32 | body.no-hotswap #CharListButtonAndHotSwaps .flex-container { | ||
| 33 | flex-wrap: nowrap; | ||
| 34 | align-items: flex-end; | ||
| 35 | flex-flow: row; | ||
| 36 | } | ||
| 37 | |||
| 31 | body.hideChatAvatars .last_mes:not(.smallSysMes) { | 38 | body.hideChatAvatars .last_mes:not(.smallSysMes) { |
| 32 | padding-bottom: 20px !important; | 39 | padding-bottom: 20px !important; |
| 33 | } | 40 | } |
| @@ -142,12 +142,28 @@ body.hideChatAvatars .welcomePanel .recentChatList .recentChat .avatar { | |||
| 142 | justify-content: space-between; | 142 | justify-content: space-between; |
| 143 | align-items: baseline; | 143 | align-items: baseline; |
| 144 | font-size: calc(var(--mainFontSize) * 1); | 144 | font-size: calc(var(--mainFontSize) * 1); |
| 145 | gap: 5px; | ||
| 145 | } | 146 | } |
| 146 | 147 | ||
| 147 | .welcomeRecent .recentChatList .recentChat .chatNameContainer .chatName { | 148 | .welcomeRecent .recentChatList .recentChat .chatNameContainer .chatName { |
| 148 | white-space: nowrap; | 149 | white-space: nowrap; |
| 149 | text-overflow: ellipsis; | 150 | text-overflow: ellipsis; |
| 150 | overflow: hidden; | 151 | overflow: hidden; |
| 152 | flex: 1; | ||
| 153 | } | ||
| 154 | |||
| 155 | .welcomeRecent .recentChatList .recentChat .chatActions { | ||
| 156 | display: flex; | ||
| 157 | flex-direction: row; | ||
| 158 | align-items: center; | ||
| 159 | justify-content: center; | ||
| 160 | gap: 5px; | ||
| 161 | } | ||
| 162 | |||
| 163 | .welcomeRecent .recentChatList .recentChat .chatActions button { | ||
| 164 | margin: 0; | ||
| 165 | font-size: 0.8em; | ||
| 166 | cursor: pointer; | ||
| 151 | } | 167 | } |
| 152 | 168 | ||
| 153 | .welcomeRecent .recentChatList .recentChat .chatMessageContainer { | 169 | .welcomeRecent .recentChatList .recentChat .chatMessageContainer { |
| @@ -198,7 +198,11 @@ | |||
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | .world_entry { | 200 | .world_entry { |
| 201 | transition: opacity 500ms; | 201 | transition: opacity var(--animation-duration-3x); |
| 202 | } | ||
| 203 | |||
| 204 | .world_entry_edit { | ||
| 205 | display: contents; | ||
| 202 | } | 206 | } |
| 203 | 207 | ||
| 204 | .disabledWIEntry { | 208 | .disabledWIEntry { |
| @@ -267,7 +271,7 @@ select.keyselect+span.select2-container .select2-selection--multiple { | |||
| 267 | 271 | ||
| 268 | opacity: 0.5; | 272 | opacity: 0.5; |
| 269 | color: var(--SmartThemeBodyColor); | 273 | color: var(--SmartThemeBodyColor); |
| 270 | transition: opacity 0.3s; | 274 | transition: opacity var(--animation-duration-2x); |
| 271 | } | 275 | } |
| 272 | 276 | ||
| 273 | .switch_input_type_icon:hover { | 277 | .switch_input_type_icon:hover { |
| @@ -1,6 +1,7 @@ | |||
| 1 | import libs from './lib'; | 1 | import libs from './lib'; |
| 2 | import getContext from './scripts/st-context'; | 2 | import getContext from './scripts/st-context'; |
| 3 | import { power_user } from './scripts/power-user'; | 3 | import { power_user } from './scripts/power-user'; |
| 4 | import { QuickReplyApi } from './scripts/extensions/quick-reply/api/QuickReplyApi'; | ||
| 4 | 5 | ||
| 5 | declare global { | 6 | declare global { |
| 6 | // Custom types | 7 | // Custom types |
| @@ -13,6 +14,7 @@ declare global { | |||
| 13 | 14 | ||
| 14 | declare var pdfjsLib; | 15 | declare var pdfjsLib; |
| 15 | declare var ePub; | 16 | declare var ePub; |
| 17 | declare var quickReplyApi: QuickReplyApi; | ||
| 16 | 18 | ||
| 17 | declare var SillyTavern: { | 19 | declare var SillyTavern: { |
| 18 | getContext(): typeof getContext; | 20 | getContext(): typeof getContext; |
| @@ -30,6 +32,11 @@ declare global { | |||
| 30 | izoomify(options?: any): JQuery; | 32 | izoomify(options?: any): JQuery; |
| 31 | } | 33 | } |
| 32 | 34 | ||
| 35 | // NPM package doesn't have the 'queue' property in the type definition | ||
| 36 | interface JQueryTransitOptions { | ||
| 37 | queue?: boolean; | ||
| 38 | } | ||
| 39 | |||
| 33 | namespace Select2 { | 40 | namespace Select2 { |
| 34 | interface Options<Result = DataFormat | GroupedDataFormat, RemoteResult = any> { | 41 | interface Options<Result = DataFormat | GroupedDataFormat, RemoteResult = any> { |
| 35 | /** | 42 | /** |
| @@ -0,0 +1,4 @@ | |||
| 1 | <svg width="24" height="21" viewBox="0 0 24 21" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | <path d="M22.8059 9.20726C23.2424 9.96331 23.2424 10.8948 22.8059 11.6508L18.2791 19.4915C17.8426 20.2475 17.0359 20.7133 16.1629 20.7133H7.10934C6.23633 20.7133 5.42964 20.2475 4.99313 19.4915L0.466342 11.6508C0.0298381 10.8948 0.02984 9.96331 0.466344 9.20726L4.99313 1.36663C5.42964 0.61058 6.23633 0.144836 7.10934 0.144836H16.1629C17.0359 0.144836 17.8426 0.610581 18.2791 1.36663L22.8059 9.20726Z" /> | ||
| 3 | <path fill-rule="evenodd" clip-rule="evenodd" d="M6.66791 13.8818C6.49765 13.8818 6.32633 13.8275 6.18162 13.7168C5.83259 13.4476 5.76662 12.9464 6.03583 12.5974L9.22068 8.45807C9.3505 8.28888 9.5431 8.17928 9.75379 8.15268C9.96874 8.12501 10.1794 8.1846 10.3465 8.31761L13.3472 10.6746L15.9724 7.28756C16.2427 6.93748 16.7428 6.87257 17.0918 7.14498C17.4408 7.41526 17.5047 7.91645 17.2344 8.26441L14.1166 12.2867C13.9868 12.4548 13.7952 12.5644 13.5845 12.59C13.3717 12.6187 13.161 12.557 12.9929 12.4261L9.99428 10.0702L7.30105 13.57C7.14356 13.7743 6.90733 13.8818 6.66791 13.8818Z" fill="black"/> | ||
| 4 | </svg> | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <svg version="1.1" viewBox="0 0 21.773 24.84" xmlns="http://www.w3.org/2000/svg"> | ||
| 3 | <path d="m21.576 14.91a1 1 0 0 0-1.4-0.22l-9.29 6.86v0.29a1 1 0 1 1 0 1.91v0.05a1 1 0 0 0 0.6-0.19l9.88-7.3a1 1 0 0 0 0.21-1.4z"/> | ||
| 4 | <path d="m10.886 23.75a1 1 0 1 1 0-1.91v-0.29l-9.29-6.86a1 1 0 0 0-1.4 0.22 1 1 0 0 0 0.21 1.4l9.89 7.3a1 1 0 0 0 0.59 0.19z"/> | ||
| 5 | <path d="m10.886 20.84a2 2 0 1 0 2 2 2 2 0 0 0-2-2zm0 2.91a1 1 0 1 1 1-0.95 1 1 0 0 1-1 0.95z"/> | ||
| 6 | <path d="m2.8864 4.52a1 1 0 0 1-1-1v-2.51a1 1 0 1 1 2 0v2.51a1 1 0 0 1-1 1z"/> | ||
| 7 | <circle cx="2.8564" cy="12.38" r="1.01"/> | ||
| 8 | <circle cx="2.8564" cy="9.43" r="1.01"/> | ||
| 9 | <circle cx="2.8564" cy="6.47" r="1.01"/> | ||
| 10 | <path d="m18.886 7.45a1 1 0 0 1-1-1v-2.52a1 1 0 0 1 2 0v2.52a1 1 0 0 1-1 1z"/> | ||
| 11 | <circle cx="18.916" cy="12.39" r="1.01"/> | ||
| 12 | <circle cx="18.916" cy="9.4" r="1.01"/> | ||
| 13 | <circle cx="18.916" cy="1.01" r="1.01"/> | ||
| 14 | <path d="m10.886 16.38a1 1 0 0 1-1-1v-2.54a1 1 0 0 1 2 0v2.54a1 1 0 0 1-1 1z"/> | ||
| 15 | <circle cx="10.886" cy="18.31" r="1.01"/> | ||
| 16 | <circle cx="10.886" cy="9.89" r="1.01"/> | ||
| 17 | <circle cx="10.886" cy="6.94" r="1.01"/> | ||
| 18 | <path d="m14.886 10.43a1 1 0 0 1-1-1v-2.51a1 1 0 1 1 2 0v2.51a1 1 0 0 1-1 1z"/> | ||
| 19 | <circle cx="14.906" cy="3.96" r="1.01"/> | ||
| 20 | <circle cx="14.906" cy="15.3" r="1.01"/> | ||
| 21 | <circle cx="14.906" cy="12.35" r="1.01"/> | ||
| 22 | <circle cx="6.8664" cy="15.3" r="1.01"/> | ||
| 23 | <circle cx="6.8664" cy="6.94" r="1.01"/> | ||
| 24 | <circle cx="6.8664" cy="3.96" r="1.01"/> | ||
| 25 | <path d="m6.8864 13.38a1 1 0 0 1-1-1v-2.54a1 1 0 0 1 2 0v2.54a1 1 0 0 1-1 1z"/> | ||
| 26 | </svg> | ||
| @@ -140,7 +140,7 @@ | |||
| 140 | <div data-preset-manager-import="novel" class="margin0 menu_button_icon menu_button" title="Import preset" data-i18n="[title]Import preset"> | 140 | <div data-preset-manager-import="novel" class="margin0 menu_button_icon menu_button" title="Import preset" data-i18n="[title]Import preset"> |
| 141 | <i class="fa-fw fa-solid fa-file-import"></i> | 141 | <i class="fa-fw fa-solid fa-file-import"></i> |
| 142 | </div> | 142 | </div> |
| 143 | <div data-preset-manager-export="novel" class="margin0 menu_button_icon menu_button" title="Export preset" data-i18n="[title]Export preset"> | 143 | <div data-preset-manager-export="novel" class="margin0 menu_button_icon menu_button" title="Export preset" data-i18n="[title]Export preset"> |
| 144 | <i class="fa-fw fa-solid fa-file-export"></i> | 144 | <i class="fa-fw fa-solid fa-file-export"></i> |
| 145 | </div> | 145 | </div> |
| 146 | <div data-preset-manager-delete="novel" class="margin0 menu_button_icon menu_button" title="Delete the preset" data-i18n="[title]Delete the preset"> | 146 | <div data-preset-manager-delete="novel" class="margin0 menu_button_icon menu_button" title="Delete the preset" data-i18n="[title]Delete the preset"> |
| @@ -652,7 +652,7 @@ | |||
| 652 | <input type="number" id="openai_max_tokens" name="openai_max_tokens" class="text_pole" min="1" max="65536"> | 652 | <input type="number" id="openai_max_tokens" name="openai_max_tokens" class="text_pole" min="1" max="65536"> |
| 653 | </div> | 653 | </div> |
| 654 | </div> | 654 | </div> |
| 655 | <div class="range-block" data-source="openai,custom,xai"> | 655 | <div class="range-block" data-source="openai,custom,xai,aimlapi"> |
| 656 | <div class="range-block-title" data-i18n="Multiple swipes per generation"> | 656 | <div class="range-block-title" data-i18n="Multiple swipes per generation"> |
| 657 | Multiple swipes per generation | 657 | Multiple swipes per generation |
| 658 | </div> | 658 | </div> |
| @@ -661,9 +661,9 @@ | |||
| 661 | </div> | 661 | </div> |
| 662 | </div> | 662 | </div> |
| 663 | <div data-source="openrouter" class="range-block"> | 663 | <div data-source="openrouter" class="range-block"> |
| 664 | <div class="range-block-title" title="Allow compressing requests by removing messages from the middle of the prompt."> | 664 | <div class="range-block-title" data-i18n="[title]Allow compressing requests by removing messages from the middle of the prompt." title="Allow compressing requests by removing messages from the middle of the prompt."> |
| 665 | <span data-i18n="Middle-out Transform">Middle-out Transform</span> | 665 | <span data-i18n="Middle-out Transform">Middle-out Transform</span> |
| 666 | <a href="https://openrouter.ai/docs/transforms" target="_blank" rel="noreferrer noopener" class="note-link-span fa-solid fa-circle-question"></a> | 666 | <a href="https://openrouter.ai/docs/transforms" target="_blank" rel="noreferrer noopener" class="note-link-span fa-solid fa-circle-question"></a> |
| 667 | </div> | 667 | </div> |
| 668 | <div class="wide100p"> | 668 | <div class="wide100p"> |
| 669 | <select id="openrouter_middleout" class="text_pole"> | 669 | <select id="openrouter_middleout" class="text_pole"> |
| @@ -674,7 +674,7 @@ | |||
| 674 | </div> | 674 | </div> |
| 675 | </div> | 675 | </div> |
| 676 | <div data-source="openrouter"> | 676 | <div data-source="openrouter"> |
| 677 | Max prompt cost: <span id="openrouter_max_prompt_cost">Unknown</span> | 677 | <span data-i18n="Max prompt cost:">Max prompt cost:</span> <span id="openrouter_max_prompt_cost" data-i18n="Unknown">Unknown</span> |
| 678 | </div> | 678 | </div> |
| 679 | <hr> | 679 | <hr> |
| 680 | <div class="range-block"> | 680 | <div class="range-block"> |
| @@ -691,7 +691,7 @@ | |||
| 691 | </span> | 691 | </span> |
| 692 | </div> | 692 | </div> |
| 693 | </div> | 693 | </div> |
| 694 | <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai,pollinations"> | 694 | <div class="range-block" data-source="openai,claude,windowai,aimlapi,openrouter,ai21,scale,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai,pollinations"> |
| 695 | <div class="range-block-title" data-i18n="Temperature"> | 695 | <div class="range-block-title" data-i18n="Temperature"> |
| 696 | Temperature | 696 | Temperature |
| 697 | </div> | 697 | </div> |
| @@ -704,7 +704,7 @@ | |||
| 704 | </div> | 704 | </div> |
| 705 | </div> | 705 | </div> |
| 706 | </div> | 706 | </div> |
| 707 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai,pollinations"> | 707 | <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai,pollinations"> |
| 708 | <div class="range-block-title" data-i18n="Frequency Penalty"> | 708 | <div class="range-block-title" data-i18n="Frequency Penalty"> |
| 709 | Frequency Penalty | 709 | Frequency Penalty |
| 710 | </div> | 710 | </div> |
| @@ -717,7 +717,7 @@ | |||
| 717 | </div> | 717 | </div> |
| 718 | </div> | 718 | </div> |
| 719 | </div> | 719 | </div> |
| 720 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai,pollinations"> | 720 | <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai,pollinations"> |
| 721 | <div class="range-block-title" data-i18n="Presence Penalty"> | 721 | <div class="range-block-title" data-i18n="Presence Penalty"> |
| 722 | Presence Penalty | 722 | Presence Penalty |
| 723 | </div> | 723 | </div> |
| @@ -730,7 +730,7 @@ | |||
| 730 | </div> | 730 | </div> |
| 731 | </div> | 731 | </div> |
| 732 | </div> | 732 | </div> |
| 733 | <div class="range-block" data-source="claude,openrouter,makersuite,vertexai,cohere,perplexity"> | 733 | <div class="range-block" data-source="claude,aimlapi,openrouter,makersuite,vertexai,cohere,perplexity"> |
| 734 | <div class="range-block-title" data-i18n="Top K"> | 734 | <div class="range-block-title" data-i18n="Top K"> |
| 735 | Top K | 735 | Top K |
| 736 | </div> | 736 | </div> |
| @@ -743,7 +743,7 @@ | |||
| 743 | </div> | 743 | </div> |
| 744 | </div> | 744 | </div> |
| 745 | </div> | 745 | </div> |
| 746 | <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai,pollinations"> | 746 | <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,scale,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai,pollinations"> |
| 747 | <div class="range-block-title" data-i18n="Top P"> | 747 | <div class="range-block-title" data-i18n="Top P"> |
| 748 | Top P | 748 | Top P |
| 749 | </div> | 749 | </div> |
| @@ -980,7 +980,7 @@ | |||
| 980 | </div> | 980 | </div> |
| 981 | </div> | 981 | </div> |
| 982 | </div> | 982 | </div> |
| 983 | <div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq,nanogpt,xai,pollinations"> | 983 | <div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq,nanogpt,xai,pollinations,aimlapi"> |
| 984 | <div class="range-block-title justifyLeft" data-i18n="Seed"> | 984 | <div class="range-block-title justifyLeft" data-i18n="Seed"> |
| 985 | Seed | 985 | Seed |
| 986 | </div> | 986 | </div> |
| @@ -1969,7 +1969,7 @@ | |||
| 1969 | </span> | 1969 | </span> |
| 1970 | </div> | 1970 | </div> |
| 1971 | </div> | 1971 | </div> |
| 1972 | <div class="range-block" data-source="makersuite,vertexai,openrouter,claude"> | 1972 | <div class="range-block" data-source="makersuite,vertexai,aimlapi,openrouter,claude,xai"> |
| 1973 | <label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand"> | 1973 | <label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand"> |
| 1974 | <input id="openai_enable_web_search" type="checkbox" /> | 1974 | <input id="openai_enable_web_search" type="checkbox" /> |
| 1975 | <span data-i18n="Enable web search">Enable web search</span> | 1975 | <span data-i18n="Enable web search">Enable web search</span> |
| @@ -1983,7 +1983,7 @@ | |||
| 1983 | </b> | 1983 | </b> |
| 1984 | </div> | 1984 | </div> |
| 1985 | </div> | 1985 | </div> |
| 1986 | <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite,vertexai,ai21,xai,pollinations"> | 1986 | <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,aimlapi,openrouter,groq,deepseek,makersuite,vertexai,ai21,xai,pollinations"> |
| 1987 | <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand"> | 1987 | <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand"> |
| 1988 | <input id="openai_function_calling" type="checkbox" /> | 1988 | <input id="openai_function_calling" type="checkbox" /> |
| 1989 | <span data-i18n="Enable function calling">Enable function calling</span> | 1989 | <span data-i18n="Enable function calling">Enable function calling</span> |
| @@ -1991,10 +1991,10 @@ | |||
| 1991 | <div class="flexBasis100p toggle-description justifyLeft"> | 1991 | <div class="flexBasis100p toggle-description justifyLeft"> |
| 1992 | <span data-i18n="enable_functions_desc_1">Allows using </span><a href="https://platform.openai.com/docs/guides/function-calling" target="_blank" data-i18n="enable_functions_desc_2">function tools</a>. | 1992 | <span data-i18n="enable_functions_desc_1">Allows using </span><a href="https://platform.openai.com/docs/guides/function-calling" target="_blank" data-i18n="enable_functions_desc_2">function tools</a>. |
| 1993 | <span data-i18n="enable_functions_desc_3">Can be utilized by various extensions to provide additional functionality.</span> | 1993 | <span data-i18n="enable_functions_desc_3">Can be utilized by various extensions to provide additional functionality.</span> |
| 1994 | <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing is used!</strong> | 1994 | <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong> |
| 1995 | </div> | 1995 | </div> |
| 1996 | </div> | 1996 | </div> |
| 1997 | <div class="range-block" data-source="openai,openrouter,mistralai,makersuite,vertexai,claude,custom,01ai,xai,pollinations"> | 1997 | <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,01ai,xai,pollinations"> |
| 1998 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> | 1998 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> |
| 1999 | <input id="openai_image_inlining" type="checkbox" /> | 1999 | <input id="openai_image_inlining" type="checkbox" /> |
| 2000 | <span data-i18n="Send inline images">Send inline images</span> | 2000 | <span data-i18n="Send inline images">Send inline images</span> |
| @@ -2020,6 +2020,20 @@ | |||
| 2020 | </div> | 2020 | </div> |
| 2021 | </div> | 2021 | </div> |
| 2022 | <div class="range-block" data-source="makersuite,vertexai"> | 2022 | <div class="range-block" data-source="makersuite,vertexai"> |
| 2023 | <label for="openai_video_inlining" class="checkbox_label flexWrap widthFreeExpand"> | ||
| 2024 | <input id="openai_video_inlining" type="checkbox" /> | ||
| 2025 | <span data-i18n="Send inline videos">Send inline videos</span> | ||
| 2026 | </label> | ||
| 2027 | <div id="video_inlining_hint" class="flexBasis100p toggle-description justifyLeft"> | ||
| 2028 | <span data-i18n="video_inlining_hint_1">Sends videos in prompts if the model supports it. Use the</span> | ||
| 2029 | <code><i class="fa-solid fa-paperclip"></i></code> | ||
| 2030 | <span data-i18n="video_inlining_hint_2">action on any message or the</span> | ||
| 2031 | <code><i class="fa-solid fa-wand-magic-sparkles"></i></code> | ||
| 2032 | <span data-i18n="video_inlining_hint_3">menu to attach a video file to the chat.</span> | ||
| 2033 | <strong data-i18n="video_inlining_hint_4">Videos must be less than 20 MB and under 1 minute long</strong> | ||
| 2034 | </div> | ||
| 2035 | </div> | ||
| 2036 | <div class="range-block" data-source="makersuite,vertexai"> | ||
| 2023 | <label for="openai_request_images" class="checkbox_label widthFreeExpand"> | 2037 | <label for="openai_request_images" class="checkbox_label widthFreeExpand"> |
| 2024 | <input id="openai_request_images" type="checkbox" /> | 2038 | <input id="openai_request_images" type="checkbox" /> |
| 2025 | <span> | 2039 | <span> |
| @@ -2050,7 +2064,7 @@ | |||
| 2050 | </span> | 2064 | </span> |
| 2051 | </div> | 2065 | </div> |
| 2052 | </div> | 2066 | </div> |
| 2053 | <div class="range-block" data-source="deepseek,openrouter,custom,claude,xai,makersuite"> | 2067 | <div class="range-block" data-source="deepseek,aimlapi,openrouter,custom,claude,xai,makersuite,vertexai"> |
| 2054 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> | 2068 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> |
| 2055 | <input id="openai_show_thoughts" type="checkbox" /> | 2069 | <input id="openai_show_thoughts" type="checkbox" /> |
| 2056 | <span data-i18n="Request model reasoning">Request model reasoning</span> | 2070 | <span data-i18n="Request model reasoning">Request model reasoning</span> |
| @@ -2064,7 +2078,7 @@ | |||
| 2064 | </span> | 2078 | </span> |
| 2065 | </div> | 2079 | </div> |
| 2066 | </div> | 2080 | </div> |
| 2067 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,vertexai,openrouter,pollinations"> | 2081 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,vertexai,aimlapi,openrouter,pollinations"> |
| 2068 | <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models."> | 2082 | <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models."> |
| 2069 | <label for="openai_reasoning_effort"> | 2083 | <label for="openai_reasoning_effort"> |
| 2070 | <span data-i18n="Reasoning Effort">Reasoning Effort</span> | 2084 | <span data-i18n="Reasoning Effort">Reasoning Effort</span> |
| @@ -2072,20 +2086,20 @@ | |||
| 2072 | </label> | 2086 | </label> |
| 2073 | <select id="openai_reasoning_effort"> | 2087 | <select id="openai_reasoning_effort"> |
| 2074 | <option data-i18n="openai_reasoning_effort_auto" value="auto">Auto</option> | 2088 | <option data-i18n="openai_reasoning_effort_auto" value="auto">Auto</option> |
| 2075 | <option data-i18n="openai_reasoning_effort_minimum" value="min">Mininum</option> | 2089 | <option data-i18n="openai_reasoning_effort_minimum" value="min">Minimum</option> |
| 2076 | <option data-i18n="openai_reasoning_effort_low" value="low">Low</option> | 2090 | <option data-i18n="openai_reasoning_effort_low" value="low">Low</option> |
| 2077 | <option data-i18n="openai_reasoning_effort_medium" value="medium">Medium</option> | 2091 | <option data-i18n="openai_reasoning_effort_medium" value="medium">Medium</option> |
| 2078 | <option data-i18n="openai_reasoning_effort_high" value="high">High</option> | 2092 | <option data-i18n="openai_reasoning_effort_high" value="high">High</option> |
| 2079 | <option data-i18n="openai_reasoning_effort_maximum" value="max">Maximum</option> | 2093 | <option data-i18n="openai_reasoning_effort_maximum" value="max">Maximum</option> |
| 2080 | </select> | 2094 | </select> |
| 2081 | <div class="toggle-description justifyLeft marginBot5" data-source="openai,custom,xai,openrouter" data-i18n="OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level."> | 2095 | <div class="toggle-description justifyLeft marginBot5" data-source="openai,custom,xai,aimlapi,openrouter" data-i18n="OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level."> |
| 2082 | OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level. | 2096 | OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level. |
| 2083 | </div> | 2097 | </div> |
| 2084 | <div class="toggle-description justifyLeft marginBot5" data-source="claude" data-i18n="Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking."> | 2098 | <div class="toggle-description justifyLeft marginBot5" data-source="claude" data-i18n="Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking."> |
| 2085 | Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking. | 2099 | Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking. |
| 2086 | </div> | 2100 | </div> |
| 2087 | <div class="toggle-description justifyLeft marginBot5" data-source="makersuite,vertexai" data-i18n="Allocates a portion of the response length for thinking (min: 0 tokens, low: 10%, medium: 25%, high: 50%, max: 24576 tokens). Auto lets the model decide."> | 2101 | <div class="toggle-description justifyLeft marginBot5" data-source="makersuite,vertexai" data-i18n="Allocates a portion of the response length for thinking (Flash 2.5/Pro 2.5) (min: 0/128 tokens, low: 10%, medium: 25%, high: 50%, max: 24576/32768 tokens). Auto lets the model decide."> |
| 2088 | Allocates a portion of the response length for thinking (min: 0 tokens, low: 10%, medium: 25%, high: 50%, max: 24576 tokens). Auto lets the model decide. | 2102 | Allocates a portion of the response length for thinking (Flash 2.5/Pro 2.5) (min: 0/128 tokens, low: 10%, medium: 25%, high: 50%, max: 24576/32768 tokens). Auto lets the model decide. |
| 2089 | </div> | 2103 | </div> |
| 2090 | </div> | 2104 | </div> |
| 2091 | </div> | 2105 | </div> |
| @@ -2117,7 +2131,7 @@ | |||
| 2117 | </div> | 2131 | </div> |
| 2118 | </div> | 2132 | </div> |
| 2119 | </div> | 2133 | </div> |
| 2120 | <div class="range-block m-t-1" data-source="openai,openrouter,scale,custom"> | 2134 | <div class="range-block m-t-1" data-source="openai,aimlapi,openrouter,scale,custom"> |
| 2121 | <div id="logit_bias_openai" class="range-block-title openai_restorable" data-i18n="Logit Bias"> | 2135 | <div id="logit_bias_openai" class="range-block-title openai_restorable" data-i18n="Logit Bias"> |
| 2122 | Logit Bias | 2136 | Logit Bias |
| 2123 | </div> | 2137 | </div> |
| @@ -2228,10 +2242,11 @@ | |||
| 2228 | </small> | 2242 | </small> |
| 2229 | <div class="flex-container"> | 2243 | <div class="flex-container"> |
| 2230 | <input id="horde_api_key" name="horde_api_key" class="text_pole flex1" type="text" placeholder="0000000000" autocomplete="off"> | 2244 | <input id="horde_api_key" name="horde_api_key" class="text_pole flex1" type="text" placeholder="0000000000" autocomplete="off"> |
| 2231 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_horde"></div> | 2245 | <div title="Save and connect" data-i18n="[title]Save and connect" class="menu_button fa-solid fa-plug fa-fw" id="horde_api_key_button"></div> |
| 2246 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_horde"></div> | ||
| 2232 | </div> | 2247 | </div> |
| 2233 | <div data-for="horde_api_key" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2248 | <div data-for="horde_api_key" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2234 | For privacy reasons, your API key will be hidden after you reload the page. | 2249 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2235 | </div> | 2250 | </div> |
| 2236 | <h4 class="horde_model_title"> | 2251 | <h4 class="horde_model_title"> |
| 2237 | <span data-i18n="Models">Models </span> | 2252 | <span data-i18n="Models">Models </span> |
| @@ -2283,11 +2298,11 @@ | |||
| 2283 | </span> | 2298 | </span> |
| 2284 | <div class="flex-container"> | 2299 | <div class="flex-container"> |
| 2285 | <input id="api_key_novel" name="api_key_novel" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2300 | <input id="api_key_novel" name="api_key_novel" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2286 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_novel"> | 2301 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_novel"> |
| 2287 | </div> | 2302 | </div> |
| 2288 | </div> | 2303 | </div> |
| 2289 | <div data-for="api_key_novel" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2304 | <div data-for="api_key_novel" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2290 | For privacy reasons, your API key will be hidden after you reload the page. | 2305 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2291 | </div> | 2306 | </div> |
| 2292 | <h4><span data-i18n="Novel AI Model">Novel AI Model</span> | 2307 | <h4><span data-i18n="Novel AI Model">Novel AI Model</span> |
| 2293 | <a href="https://docs.sillytavern.app/usage/api-connections/novelai/#models" class="notes-link" target="_blank"> | 2308 | <a href="https://docs.sillytavern.app/usage/api-connections/novelai/#models" class="notes-link" target="_blank"> |
| @@ -2335,10 +2350,10 @@ | |||
| 2335 | <h4 data-i18n="TogetherAI API Key">TogetherAI API Key</h4> | 2350 | <h4 data-i18n="TogetherAI API Key">TogetherAI API Key</h4> |
| 2336 | <div class="flex-container"> | 2351 | <div class="flex-container"> |
| 2337 | <input id="api_key_togetherai" name="api_key_togetherai" class="text_pole flex1" value="" type="text" autocomplete="off"> | 2352 | <input id="api_key_togetherai" name="api_key_togetherai" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 2338 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_togetherai"></div> | 2353 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_togetherai"></div> |
| 2339 | </div> | 2354 | </div> |
| 2340 | <div data-for="api_key_togetherai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2355 | <div data-for="api_key_togetherai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2341 | For privacy reasons, your API key will be hidden after you reload the page. | 2356 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2342 | </div> | 2357 | </div> |
| 2343 | <div> | 2358 | <div> |
| 2344 | <h4 data-i18n="TogetherAI Model">TogetherAI Model</h4> | 2359 | <h4 data-i18n="TogetherAI Model">TogetherAI Model</h4> |
| @@ -2359,10 +2374,10 @@ | |||
| 2359 | </div> | 2374 | </div> |
| 2360 | <div class="flex-container"> | 2375 | <div class="flex-container"> |
| 2361 | <input id="api_key_openrouter-tg" name="api_key_openrouter" class="text_pole flex1 api_key_openrouter" value="" type="text" autocomplete="off"> | 2376 | <input id="api_key_openrouter-tg" name="api_key_openrouter" class="text_pole flex1 api_key_openrouter" value="" type="text" autocomplete="off"> |
| 2362 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_openrouter"></div> | 2377 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_openrouter"></div> |
| 2363 | </div> | 2378 | </div> |
| 2364 | <div data-for="api_key_openrouter" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2379 | <div data-for="api_key_openrouter-tg" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2365 | For privacy reasons, your API key will be hidden after you reload the page. | 2380 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2366 | </div> | 2381 | </div> |
| 2367 | <div> | 2382 | <div> |
| 2368 | <h4 data-i18n="OpenRouter Model">OpenRouter Model</h4> | 2383 | <h4 data-i18n="OpenRouter Model">OpenRouter Model</h4> |
| @@ -2386,10 +2401,10 @@ | |||
| 2386 | <h4 data-i18n="InfermaticAI API Key">InfermaticAI API Key</h4> | 2401 | <h4 data-i18n="InfermaticAI API Key">InfermaticAI API Key</h4> |
| 2387 | <div class="flex-container"> | 2402 | <div class="flex-container"> |
| 2388 | <input id="api_key_infermaticai" name="api_key_infermaticai" class="text_pole flex1" value="" type="text" autocomplete="off"> | 2403 | <input id="api_key_infermaticai" name="api_key_infermaticai" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 2389 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_infermaticai"></div> | 2404 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_infermaticai"></div> |
| 2390 | </div> | 2405 | </div> |
| 2391 | <div data-for="api_key_infermaticai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2406 | <div data-for="api_key_infermaticai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2392 | For privacy reasons, your API key will be hidden after you reload the page. | 2407 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2393 | </div> | 2408 | </div> |
| 2394 | <div> | 2409 | <div> |
| 2395 | <h4 data-i18n="InfermaticAI Model">InfermaticAI Model</h4> | 2410 | <h4 data-i18n="InfermaticAI Model">InfermaticAI Model</h4> |
| @@ -2409,10 +2424,10 @@ | |||
| 2409 | </h4> | 2424 | </h4> |
| 2410 | <div class="flex-container"> | 2425 | <div class="flex-container"> |
| 2411 | <input id="api_key_dreamgen" name="api_key_dreamgen" class="text_pole flex1" value="" type="text" autocomplete="off"> | 2426 | <input id="api_key_dreamgen" name="api_key_dreamgen" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 2412 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_dreamgen"></div> | 2427 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_dreamgen"></div> |
| 2413 | </div> | 2428 | </div> |
| 2414 | <div data-for="api_key_dreamgen" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2429 | <div data-for="api_key_dreamgen" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2415 | For privacy reasons, your API key will be hidden after you reload the page. | 2430 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2416 | </div> | 2431 | </div> |
| 2417 | <div> | 2432 | <div> |
| 2418 | <h4 data-i18n="DreamGen Model">DreamGen Model</h4> | 2433 | <h4 data-i18n="DreamGen Model">DreamGen Model</h4> |
| @@ -2434,11 +2449,11 @@ | |||
| 2434 | </h4> | 2449 | </h4> |
| 2435 | <div class="flex-container"> | 2450 | <div class="flex-container"> |
| 2436 | <input id="api_key_mancer" name="api_key_mancer" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2451 | <input id="api_key_mancer" name="api_key_mancer" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2437 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_mancer"> | 2452 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_mancer"> |
| 2438 | </div> | 2453 | </div> |
| 2439 | </div> | 2454 | </div> |
| 2440 | <div data-for="api_key_mancer" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2455 | <div data-for="api_key_mancer" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2441 | For privacy reasons, your API key will be hidden after you reload the page. | 2456 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2442 | </div> | 2457 | </div> |
| 2443 | <div class="flex1"> | 2458 | <div class="flex1"> |
| 2444 | <h4 data-i18n="Mancer Model">Mancer Model</h4> | 2459 | <h4 data-i18n="Mancer Model">Mancer Model</h4> |
| @@ -2453,11 +2468,11 @@ | |||
| 2453 | <h4 data-i18n="API key (optional)">API key (optional)</h4> | 2468 | <h4 data-i18n="API key (optional)">API key (optional)</h4> |
| 2454 | <div class="flex-container"> | 2469 | <div class="flex-container"> |
| 2455 | <input id="api_key_generic" name="api_key_generic" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2470 | <input id="api_key_generic" name="api_key_generic" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2456 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_generic"> | 2471 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_generic"> |
| 2457 | </div> | 2472 | </div> |
| 2458 | </div> | 2473 | </div> |
| 2459 | <div data-for="api_key_generic" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2474 | <div data-for="api_key_generic" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2460 | For privacy reasons, your API key will be hidden after you reload the page. | 2475 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2461 | </div> | 2476 | </div> |
| 2462 | <div class="flex1"> | 2477 | <div class="flex1"> |
| 2463 | <h4 data-i18n="Server url">Server URL</h4> | 2478 | <h4 data-i18n="Server url">Server URL</h4> |
| @@ -2482,11 +2497,11 @@ | |||
| 2482 | <h4 data-i18n="API key (optional)">API key (optional)</h4> | 2497 | <h4 data-i18n="API key (optional)">API key (optional)</h4> |
| 2483 | <div class="flex-container"> | 2498 | <div class="flex-container"> |
| 2484 | <input id="api_key_ooba" name="api_key_ooba" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2499 | <input id="api_key_ooba" name="api_key_ooba" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2485 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_ooba"> | 2500 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_ooba"> |
| 2486 | </div> | 2501 | </div> |
| 2487 | </div> | 2502 | </div> |
| 2488 | <div data-for="api_key_ooba" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2503 | <div data-for="api_key_ooba" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2489 | For privacy reasons, your API key will be hidden after you reload the page. | 2504 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2490 | </div> | 2505 | </div> |
| 2491 | <div class="flex1"> | 2506 | <div class="flex1"> |
| 2492 | <h4 data-i18n="Server url">Server URL</h4> | 2507 | <h4 data-i18n="Server url">Server URL</h4> |
| @@ -2504,11 +2519,11 @@ | |||
| 2504 | <h4 data-i18n="API key (optional)">API key</h4> | 2519 | <h4 data-i18n="API key (optional)">API key</h4> |
| 2505 | <div class="flex-container"> | 2520 | <div class="flex-container"> |
| 2506 | <input id="api_key_featherless" name="api_key_featherless" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2521 | <input id="api_key_featherless" name="api_key_featherless" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2507 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_featherless"> | 2522 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_featherless"> |
| 2508 | </div> | 2523 | </div> |
| 2509 | </div> | 2524 | </div> |
| 2510 | <div data-for="api_key_featherless" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2525 | <div data-for="api_key_featherless" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2511 | For privacy reasons, your API key will be hidden after you reload the page. | 2526 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2512 | </div> | 2527 | </div> |
| 2513 | <hr> | 2528 | <hr> |
| 2514 | <h4 data-i18n="Featherless Model Selection">Featherless Model Selection</h4> | 2529 | <h4 data-i18n="Featherless Model Selection">Featherless Model Selection</h4> |
| @@ -2555,11 +2570,11 @@ | |||
| 2555 | <h4 data-i18n="vLLM API key">vLLM API key</h4> | 2570 | <h4 data-i18n="vLLM API key">vLLM API key</h4> |
| 2556 | <div class="flex-container"> | 2571 | <div class="flex-container"> |
| 2557 | <input id="api_key_vllm" name="api_key_vllm" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2572 | <input id="api_key_vllm" name="api_key_vllm" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2558 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_vllm"> | 2573 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_vllm"> |
| 2559 | </div> | 2574 | </div> |
| 2560 | </div> | 2575 | </div> |
| 2561 | <div data-for="api_key_vllm" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2576 | <div data-for="api_key_vllm" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2562 | For privacy reasons, your API key will be hidden after you reload the page. | 2577 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2563 | </div> | 2578 | </div> |
| 2564 | <div class="flex1"> | 2579 | <div class="flex1"> |
| 2565 | <h4 data-i18n="API url">API URL</h4> | 2580 | <h4 data-i18n="API url">API URL</h4> |
| @@ -2579,11 +2594,11 @@ | |||
| 2579 | <h4 data-i18n="HuggingFace Token">HuggingFace Token</h4> | 2594 | <h4 data-i18n="HuggingFace Token">HuggingFace Token</h4> |
| 2580 | <div class="flex-container"> | 2595 | <div class="flex-container"> |
| 2581 | <input id="api_key_huggingface" name="api_key_huggingface" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2596 | <input id="api_key_huggingface" name="api_key_huggingface" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2582 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_huggingface"> | 2597 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_huggingface"> |
| 2583 | </div> | 2598 | </div> |
| 2584 | </div> | 2599 | </div> |
| 2585 | <div data-for="api_key_huggingface" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2600 | <div data-for="api_key_huggingface" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2586 | For privacy reasons, your API key will be hidden after you reload the page. | 2601 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2587 | </div> | 2602 | </div> |
| 2588 | <div class="flex1"> | 2603 | <div class="flex1"> |
| 2589 | <h4 data-i18n="Endpoint URL">Endpoint URL</h4> | 2604 | <h4 data-i18n="Endpoint URL">Endpoint URL</h4> |
| @@ -2601,11 +2616,11 @@ | |||
| 2601 | <h4 data-i18n="Aphrodite API key">Aphrodite API key</h4> | 2616 | <h4 data-i18n="Aphrodite API key">Aphrodite API key</h4> |
| 2602 | <div class="flex-container"> | 2617 | <div class="flex-container"> |
| 2603 | <input id="api_key_aphrodite" name="api_key_aphrodite" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2618 | <input id="api_key_aphrodite" name="api_key_aphrodite" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2604 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_aphrodite"> | 2619 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_aphrodite"> |
| 2605 | </div> | 2620 | </div> |
| 2606 | </div> | 2621 | </div> |
| 2607 | <div data-for="api_key_aphrodite" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2622 | <div data-for="api_key_aphrodite" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2608 | For privacy reasons, your API key will be hidden after you reload the page. | 2623 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2609 | </div> | 2624 | </div> |
| 2610 | <div class="flex1"> | 2625 | <div class="flex1"> |
| 2611 | <h4 data-i18n="API url">API URL</h4> | 2626 | <h4 data-i18n="API url">API URL</h4> |
| @@ -2630,11 +2645,11 @@ | |||
| 2630 | <h4 data-i18n="API key (optional)">API key (optional)</h4> | 2645 | <h4 data-i18n="API key (optional)">API key (optional)</h4> |
| 2631 | <div class="flex-container"> | 2646 | <div class="flex-container"> |
| 2632 | <input id="api_key_llamacpp" name="api_key_llamacpp" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2647 | <input id="api_key_llamacpp" name="api_key_llamacpp" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2633 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_llamacpp"> | 2648 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_llamacpp"> |
| 2634 | </div> | 2649 | </div> |
| 2635 | </div> | 2650 | </div> |
| 2636 | <div data-for="api_key_llamacpp" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2651 | <div data-for="api_key_llamacpp" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2637 | For privacy reasons, your API key will be hidden after you reload the page. | 2652 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2638 | </div> | 2653 | </div> |
| 2639 | <div class="flex1"> | 2654 | <div class="flex1"> |
| 2640 | <h4 data-i18n="API url">API URL</h4> | 2655 | <h4 data-i18n="API url">API URL</h4> |
| @@ -2677,11 +2692,11 @@ | |||
| 2677 | <h4 data-i18n="Tabby API key">Tabby API key</h4> | 2692 | <h4 data-i18n="Tabby API key">Tabby API key</h4> |
| 2678 | <div class="flex-container"> | 2693 | <div class="flex-container"> |
| 2679 | <input id="api_key_tabby" name="api_key_tabby" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2694 | <input id="api_key_tabby" name="api_key_tabby" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2680 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_tabby"> | 2695 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_tabby"> |
| 2681 | </div> | 2696 | </div> |
| 2682 | </div> | 2697 | </div> |
| 2683 | <div data-for="api_key_tabby" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2698 | <div data-for="api_key_tabby" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2684 | For privacy reasons, your API key will be hidden after you reload the page. | 2699 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2685 | </div> | 2700 | </div> |
| 2686 | <div class="flex1"> | 2701 | <div class="flex1"> |
| 2687 | <h4 data-i18n="API url">API URL</h4> | 2702 | <h4 data-i18n="API url">API URL</h4> |
| @@ -2699,12 +2714,12 @@ | |||
| 2699 | </select> | 2714 | </select> |
| 2700 | <div class="marginTopBot5"> | 2715 | <div class="marginTopBot5"> |
| 2701 | <i class="fa-solid fa-flask"></i> | 2716 | <i class="fa-solid fa-flask"></i> |
| 2702 | <span>Experimental feature. Use at your own risk.</span> | 2717 | <span data-i18n="Experimental feature. Use at your own risk.">Experimental feature. Use at your own risk.</span> |
| 2703 | </div> | 2718 | </div> |
| 2704 | <div class="marginTopBot5"> | 2719 | <div class="marginTopBot5"> |
| 2705 | <small> | 2720 | <small> |
| 2706 | <i class="fa-solid fa-lightbulb"></i> | 2721 | <i class="fa-solid fa-lightbulb"></i> |
| 2707 | | 2722 | <span data-i18n="Tabby model hint prefix"></span> |
| 2708 | <code>inline_model_loading: True</code> | 2723 | <code>inline_model_loading: True</code> |
| 2709 | <span data-i18n="must be set in Tabby's config.yml to switch models."> | 2724 | <span data-i18n="must be set in Tabby's config.yml to switch models."> |
| 2710 | must be set in Tabby's config.yml to switch models. | 2725 | must be set in Tabby's config.yml to switch models. |
| @@ -2729,11 +2744,11 @@ | |||
| 2729 | <h4 data-i18n="koboldcpp API key (optional)">koboldcpp API key (optional)</h4> | 2744 | <h4 data-i18n="koboldcpp API key (optional)">koboldcpp API key (optional)</h4> |
| 2730 | <div class="flex-container"> | 2745 | <div class="flex-container"> |
| 2731 | <input id="api_key_koboldcpp" name="api_key_koboldcpp" class="text_pole flex1 wide100p" type="text" autocomplete="off"> | 2746 | <input id="api_key_koboldcpp" name="api_key_koboldcpp" class="text_pole flex1 wide100p" type="text" autocomplete="off"> |
| 2732 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_koboldcpp"> | 2747 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_koboldcpp"> |
| 2733 | </div> | 2748 | </div> |
| 2734 | </div> | 2749 | </div> |
| 2735 | <div data-for="api_key_koboldcpp" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2750 | <div data-for="api_key_koboldcpp" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2736 | For privacy reasons, your API key will be hidden after you reload the page. | 2751 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2737 | </div> | 2752 | </div> |
| 2738 | <div class="flex1"> | 2753 | <div class="flex1"> |
| 2739 | <h4 data-i18n="API url">API URL</h4> | 2754 | <h4 data-i18n="API url">API URL</h4> |
| @@ -2774,12 +2789,13 @@ | |||
| 2774 | <optgroup> | 2789 | <optgroup> |
| 2775 | <option value="01ai">01.AI (Yi)</option> | 2790 | <option value="01ai">01.AI (Yi)</option> |
| 2776 | <option value="ai21">AI21</option> | 2791 | <option value="ai21">AI21</option> |
| 2792 | <option value="aimlapi">AI/ML API</option> | ||
| 2777 | <option value="claude">Claude</option> | 2793 | <option value="claude">Claude</option> |
| 2778 | <option value="cohere">Cohere</option> | 2794 | <option value="cohere">Cohere</option> |
| 2779 | <option value="deepseek">DeepSeek</option> | 2795 | <option value="deepseek">DeepSeek</option> |
| 2780 | <option value="groq">Groq</option> | 2796 | <option value="groq">Groq</option> |
| 2781 | <option value="makersuite">Google AI Studio</option> | 2797 | <option value="makersuite">Google AI Studio</option> |
| 2782 | <option value="vertexai">Google Vertex AI (Express mode)</option> | 2798 | <option value="vertexai">Google Vertex AI</option> |
| 2783 | <option value="mistralai">MistralAI</option> | 2799 | <option value="mistralai">MistralAI</option> |
| 2784 | <option value="nanogpt">NanoGPT</option> | 2800 | <option value="nanogpt">NanoGPT</option> |
| 2785 | <option value="openrouter">OpenRouter</option> | 2801 | <option value="openrouter">OpenRouter</option> |
| @@ -2836,7 +2852,7 @@ | |||
| 2836 | <input id="openai_reverse_proxy" type="text" class="text_pole" placeholder="https://api.openai.com/v1" /> | 2852 | <input id="openai_reverse_proxy" type="text" class="text_pole" placeholder="https://api.openai.com/v1" /> |
| 2837 | <small class="reverse_proxy_warning"> | 2853 | <small class="reverse_proxy_warning"> |
| 2838 | <span data-i18n="Doesn't work? Try adding">Doesn't work? Try adding</span> <code>/v1</code> <span data-i18n="at the end!">at the end!</span> | 2854 | <span data-i18n="Doesn't work? Try adding">Doesn't work? Try adding</span> <code>/v1</code> <span data-i18n="at the end!">at the end!</span> |
| 2839 | <code>/chat/completions</code> <b data-i18n="suffix will be added automatically.">suffix will be added automatically.</b> | 2855 | <span data-i18n="completions note prefix"></span><code>/chat/completions</code> <b data-i18n="suffix will be added automatically.">suffix will be added automatically.</b> |
| 2840 | </small> | 2856 | </small> |
| 2841 | </div> | 2857 | </div> |
| 2842 | <div class="range-block-title justifyLeft" data-i18n="Proxy Password"> | 2858 | <div class="range-block-title justifyLeft" data-i18n="Proxy Password"> |
| @@ -2891,15 +2907,15 @@ | |||
| 2891 | </span> | 2907 | </span> |
| 2892 | <div class="flex-container"> | 2908 | <div class="flex-container"> |
| 2893 | <input id="api_key_openai" name="api_key_openai" class="text_pole flex1" value="" type="text" autocomplete="off"> | 2909 | <input id="api_key_openai" name="api_key_openai" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 2894 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_openai"></div> | 2910 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_openai"></div> |
| 2895 | </div> | 2911 | </div> |
| 2896 | <div id="ReverseProxyWarningMessage2" class="reverse_proxy_warning"> | 2912 | <div id="ReverseProxyWarningMessage2" class="reverse_proxy_warning"> |
| 2897 | <b data-i18n="Use Proxy password field instead. This input will be ignored."> | 2913 | <b data-i18n="Use Proxy password field instead. This input will be ignored."> |
| 2898 | Use "Proxy password" field instead. This input will be ignored. | 2914 | Use "Proxy password" field instead. This input will be ignored. |
| 2899 | </b> | 2915 | </b> |
| 2900 | </div> | 2916 | </div> |
| 2901 | <div data-for="api_key_openai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 2917 | <div data-for="api_key_openai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2902 | For privacy reasons, your API key will be hidden after you reload the page. | 2918 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2903 | </div> | 2919 | </div> |
| 2904 | <div> | 2920 | <div> |
| 2905 | <h4 data-i18n="OpenAI Model">OpenAI Model</h4> | 2921 | <h4 data-i18n="OpenAI Model">OpenAI Model</h4> |
| @@ -2985,10 +3001,10 @@ | |||
| 2985 | </div> | 3001 | </div> |
| 2986 | <div class="flex-container"> | 3002 | <div class="flex-container"> |
| 2987 | <input id="api_key_claude" name="api_key_claude" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3003 | <input id="api_key_claude" name="api_key_claude" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 2988 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_claude"></div> | 3004 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_claude"></div> |
| 2989 | </div> | 3005 | </div> |
| 2990 | <div data-for="api_key_claude" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3006 | <div data-for="api_key_claude" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 2991 | For privacy reasons, your API key will be hidden after you reload the page. | 3007 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 2992 | </div> | 3008 | </div> |
| 2993 | <div> | 3009 | <div> |
| 2994 | <h4 data-i18n="Claude Model">Claude Model</h4> | 3010 | <h4 data-i18n="Claude Model">Claude Model</h4> |
| @@ -3044,10 +3060,10 @@ | |||
| 3044 | </div> | 3060 | </div> |
| 3045 | <div class="flex-container"> | 3061 | <div class="flex-container"> |
| 3046 | <input id="api_key_openrouter" name="api_key_openrouter" class="text_pole flex1 api_key_openrouter" value="" type="text" autocomplete="off"> | 3062 | <input id="api_key_openrouter" name="api_key_openrouter" class="text_pole flex1 api_key_openrouter" value="" type="text" autocomplete="off"> |
| 3047 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_openrouter"></div> | 3063 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_openrouter"></div> |
| 3048 | </div> | 3064 | </div> |
| 3049 | <div data-for="api_key_openrouter" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3065 | <div data-for="api_key_openrouter" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3050 | For privacy reasons, your API key will be hidden after you reload the page. | 3066 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3051 | </div> | 3067 | </div> |
| 3052 | <div> | 3068 | <div> |
| 3053 | <h4 data-i18n="OpenRouter Model">OpenRouter Model</h4> | 3069 | <h4 data-i18n="OpenRouter Model">OpenRouter Model</h4> |
| @@ -3108,10 +3124,10 @@ | |||
| 3108 | <h4 data-i18n="Scale API Key">Scale API Key</h4> | 3124 | <h4 data-i18n="Scale API Key">Scale API Key</h4> |
| 3109 | <div class="flex-container"> | 3125 | <div class="flex-container"> |
| 3110 | <input id="api_key_scale" name="api_key_scale" class="text_pole flex1" value="" autocomplete="off"> | 3126 | <input id="api_key_scale" name="api_key_scale" class="text_pole flex1" value="" autocomplete="off"> |
| 3111 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_scale"></div> | 3127 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_scale"></div> |
| 3112 | </div> | 3128 | </div> |
| 3113 | <div data-for="api_key_scale" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3129 | <div data-for="api_key_scale" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3114 | For privacy reasons, your API key will be hidden after you reload the page. | 3130 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3115 | </div> | 3131 | </div> |
| 3116 | <h4>Scale API URL</h4> | 3132 | <h4>Scale API URL</h4> |
| 3117 | <input id="api_url_scale" name="api_url_scale" class="text_pole" value="" autocomplete="off" placeholder="https://dashboard.scale.com/spellbook/api/v2/deploy/xxxxxxx"> | 3133 | <input id="api_url_scale" name="api_url_scale" class="text_pole" value="" autocomplete="off" placeholder="https://dashboard.scale.com/spellbook/api/v2/deploy/xxxxxxx"> |
| @@ -3120,10 +3136,10 @@ | |||
| 3120 | <h4>Scale Cookie (_jwt)</h4> | 3136 | <h4>Scale Cookie (_jwt)</h4> |
| 3121 | <div class="flex-container"> | 3137 | <div class="flex-container"> |
| 3122 | <input id="scale_cookie" name="scale_cookie" class="text_pole flex1" value="" autocomplete="off"> | 3138 | <input id="scale_cookie" name="scale_cookie" class="text_pole flex1" value="" autocomplete="off"> |
| 3123 | <div title="Clear your cookie" data-i18n="[title]Clear your cookie" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="scale_cookie"></div> | 3139 | <div title="Clear your cookie" data-i18n="[title]Clear your cookie" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="scale_cookie"></div> |
| 3124 | </div> | 3140 | </div> |
| 3125 | <div data-for="scale_cookie" class="neutral_warning"> | 3141 | <div data-for="scale_cookie" class="neutral_warning"> |
| 3126 | For privacy reasons, your cookie will be hidden after you reload the page. | 3142 | For privacy reasons, your cookie will be hidden after you click 'Connect'. |
| 3127 | </div> | 3143 | </div> |
| 3128 | </div> | 3144 | </div> |
| 3129 | <!-- Its only purpose is to trigger max context size check --> | 3145 | <!-- Its only purpose is to trigger max context size check --> |
| @@ -3137,10 +3153,10 @@ | |||
| 3137 | <h4 data-i18n="AI21 API Key">AI21 API Key</h4> | 3153 | <h4 data-i18n="AI21 API Key">AI21 API Key</h4> |
| 3138 | <div class="flex-container"> | 3154 | <div class="flex-container"> |
| 3139 | <input id="api_key_ai21" name="api_key_ai21" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3155 | <input id="api_key_ai21" name="api_key_ai21" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3140 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_ai21"></div> | 3156 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_ai21"></div> |
| 3141 | </div> | 3157 | </div> |
| 3142 | <div data-for="api_key_ai21" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3158 | <div data-for="api_key_ai21" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3143 | For privacy reasons, your API key will be hidden after you reload the page. | 3159 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3144 | </div> | 3160 | </div> |
| 3145 | <div> | 3161 | <div> |
| 3146 | <h4 data-i18n="AI21 Model">AI21 Model</h4> | 3162 | <h4 data-i18n="AI21 Model">AI21 Model</h4> |
| @@ -3167,20 +3183,24 @@ | |||
| 3167 | <h4 data-i18n="Google AI Studio API Key">Google AI Studio API Key</h4> | 3183 | <h4 data-i18n="Google AI Studio API Key">Google AI Studio API Key</h4> |
| 3168 | <div class="flex-container"> | 3184 | <div class="flex-container"> |
| 3169 | <input id="api_key_makersuite" name="api_key_makersuite" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3185 | <input id="api_key_makersuite" name="api_key_makersuite" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3170 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_makersuite"></div> | 3186 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_makersuite"></div> |
| 3171 | </div> | 3187 | </div> |
| 3172 | <div data-for="api_key_makersuite" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3188 | <div data-for="api_key_makersuite" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3173 | For privacy reasons, your API key will be hidden after you reload the page. | 3189 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3174 | </div> | 3190 | </div> |
| 3175 | <div> | 3191 | <div> |
| 3176 | <h4 data-i18n="Google Model">Google Model</h4> | 3192 | <h4 data-i18n="Google Model">Google Model</h4> |
| 3177 | <select id="model_google_select"> | 3193 | <select id="model_google_select"> |
| 3178 | <optgroup label="Gemini 2.5"> | 3194 | <optgroup label="Gemini 2.5"> |
| 3195 | <option value="gemini-2.5-pro">gemini-2.5-pro</option> | ||
| 3196 | <option value="gemini-2.5-pro-preview-06-05">gemini-2.5-pro-preview-06-05</option> | ||
| 3179 | <option value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> | 3197 | <option value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> |
| 3180 | <option value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> | 3198 | <option value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> |
| 3181 | <option value="gemini-2.5-pro-exp-03-25">gemini-2.5-pro-exp-03-25</option> | 3199 | <option value="gemini-2.5-pro-exp-03-25">gemini-2.5-pro-exp-03-25</option> |
| 3200 | <option value="gemini-2.5-flash">gemini-2.5-flash</option> | ||
| 3182 | <option value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> | 3201 | <option value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> |
| 3183 | <option value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | 3202 | <option value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> |
| 3203 | <option value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> | ||
| 3184 | </optgroup> | 3204 | </optgroup> |
| 3185 | <optgroup label="Gemini 2.0"> | 3205 | <optgroup label="Gemini 2.0"> |
| 3186 | <option value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05 → 2.5-pro-exp-03-25</option> | 3206 | <option value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05 → 2.5-pro-exp-03-25</option> |
| @@ -3212,6 +3232,7 @@ | |||
| 3212 | <option value="gemini-1.5-flash-8b">gemini-1.5-flash-8b</option> | 3232 | <option value="gemini-1.5-flash-8b">gemini-1.5-flash-8b</option> |
| 3213 | </optgroup> | 3233 | </optgroup> |
| 3214 | <optgroup label="Gemma"> | 3234 | <optgroup label="Gemma"> |
| 3235 | <option value="gemma-3n-e4b-it">gemma-3n-e4b-it</option> | ||
| 3215 | <option value="gemma-3-27b-it">gemma-3-27b-it</option> | 3236 | <option value="gemma-3-27b-it">gemma-3-27b-it</option> |
| 3216 | <option value="gemma-3-12b-it">gemma-3-12b-it</option> | 3237 | <option value="gemma-3-12b-it">gemma-3-12b-it</option> |
| 3217 | <option value="gemma-3-4b-it">gemma-3-4b-it</option> | 3238 | <option value="gemma-3-4b-it">gemma-3-4b-it</option> |
| @@ -3219,37 +3240,145 @@ | |||
| 3219 | </optgroup> | 3240 | </optgroup> |
| 3220 | <optgroup label="LearnLM"> | 3241 | <optgroup label="LearnLM"> |
| 3221 | <option value="learnlm-2.0-flash-experimental">learnlm-2.0-flash-experimental</option> | 3242 | <option value="learnlm-2.0-flash-experimental">learnlm-2.0-flash-experimental</option> |
| 3222 | <option value="learnlm-1.5-pro-experimental">learnlm-1.5-pro-experimental</option> | ||
| 3223 | </optgroup> | 3243 | </optgroup> |
| 3244 | <optgroup id="google_other_models" label="Other"></optgroup> | ||
| 3224 | </select> | 3245 | </select> |
| 3225 | </div> | 3246 | </div> |
| 3226 | </form> | 3247 | </form> |
| 3227 | <div id="vertexai_form" data-source="vertexai"> | 3248 | <div id="vertexai_form" data-source="vertexai"> |
| 3228 | <h4> | 3249 | <h4 data-i18n="Google Vertex AI Configuration">Google Vertex AI Configuration</h4> |
| 3229 | <span data-i18n="Google Vertex AI API Key"> | 3250 | |
| 3230 | Google Vertex AI API Key | 3251 | <!-- Authentication Mode Selection --> |
| 3231 | </span> | ||
| 3232 | <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/start/express-mode/overview" data-i18n="(Express mode keys only)" target="_blank" rel="noopener noreferrer"> | ||
| 3233 | (Express mode keys only) | ||
| 3234 | </a> | ||
| 3235 | </h4> | ||
| 3236 | <div class="flex-container"> | 3252 | <div class="flex-container"> |
| 3237 | <input id="api_key_vertexai" name="api_key_vertexai" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3253 | <label for="vertexai_auth_mode" data-i18n="Authentication Mode">Authentication Mode:</label> |
| 3238 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_vertexai"></div> | 3254 | <select id="vertexai_auth_mode" class="text_pole"> |
| 3255 | <option value="express" data-i18n="Express Mode (API Key)">Express Mode (API Key)</option> | ||
| 3256 | <option value="full" data-i18n="Full Version (Service Account)">Full Version (Service Account)</option> | ||
| 3257 | </select> | ||
| 3258 | </div> | ||
| 3259 | |||
| 3260 | <!-- Express Mode Configuration --> | ||
| 3261 | <div id="vertexai_express_config" class="vertexai-auth-section" data-mode="express"> | ||
| 3262 | <h4> | ||
| 3263 | <span data-i18n="Google Vertex AI Configuration"> | ||
| 3264 | Google Vertex AI Configuration | ||
| 3265 | </span> | ||
| 3266 | <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/start/express-mode/overview" data-i18n="(Express mode)" target="_blank" rel="noopener noreferrer"> | ||
| 3267 | (Express mode) | ||
| 3268 | </a> | ||
| 3269 | </h4> | ||
| 3270 | <!-- API Key --> | ||
| 3271 | <div class="flex-container flexFlowColumn"> | ||
| 3272 | <label for="api_key_vertexai" data-i18n="API Key">API Key:</label> | ||
| 3273 | <div class="flex-container"> | ||
| 3274 | <input id="api_key_vertexai" name="api_key_vertexai" class="text_pole flex1" value="" type="text" autocomplete="off"> | ||
| 3275 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_vertexai"></div> | ||
| 3276 | </div> | ||
| 3277 | <div data-for="api_key_vertexai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> | ||
| 3278 | For privacy reasons, your API key will be hidden after you click 'Connect'. | ||
| 3279 | </div> | ||
| 3280 | </div> | ||
| 3281 | <!-- Project ID --> | ||
| 3282 | <div class="flex-container flexFlowColumn marginTop10"> | ||
| 3283 | <label for="vertexai_express_project_id"> | ||
| 3284 | <span data-i18n="Project ID">Project ID:</span> | ||
| 3285 | </label> | ||
| 3286 | <div class="flex-container"> | ||
| 3287 | <input id="vertexai_express_project_id" name="vertexai_express_project_id" class="text_pole flex1" value="" type="text" autocomplete="off" placeholder="Enter your Project ID"> | ||
| 3288 | </div> | ||
| 3289 | <div class="toggle-description justifyLeft marginBot5"> | ||
| 3290 | <small data-i18n="Project ID is required when selecting regions other than the default (us-central1). You can find this in a model 404 error message."> | ||
| 3291 | `Project ID` is only required when selecting regions other than the default (us-central1).<br> | ||
| 3292 | You can find this in a model 404 error message. | ||
| 3293 | </small> | ||
| 3294 | </div> | ||
| 3295 | </div> | ||
| 3296 | </div> | ||
| 3297 | |||
| 3298 | <!-- Full Version Configuration --> | ||
| 3299 | <div id="vertexai_full_config" class="vertexai-auth-section" data-mode="full"> | ||
| 3300 | <h4> | ||
| 3301 | <span data-i18n="Service Account Configuration"> | ||
| 3302 | Service Account Configuration | ||
| 3303 | </span> | ||
| 3304 | <a href="https://cloud.google.com/vertex-ai/docs/authentication" target="_blank" rel="noopener noreferrer"> | ||
| 3305 | <i class="fa-solid fa-circle-question"></i> | ||
| 3306 | </a> | ||
| 3307 | </h4> | ||
| 3308 | <!-- Service Account JSON Content --> | ||
| 3309 | <div class="flex-container flexFlowColumn"> | ||
| 3310 | <label for="vertexai_service_account_json" data-i18n="Service Account JSON Content">Service Account JSON Content:</label> | ||
| 3311 | <div id="vertexai_service_account_status" class="info-block marginTopBot5" style="display: none;"> | ||
| 3312 | <span id="vertexai_service_account_info"></span> | ||
| 3313 | </div> | ||
| 3314 | <div class="flex-container"> | ||
| 3315 | <input id="vertexai_service_account_json" name="vertexai_service_account_json" class="text_pole flex1" value="" type="text" autocomplete="off"> | ||
| 3316 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="vertexai_service_account_json"></div> | ||
| 3317 | </div> | ||
| 3318 | <div data-for="vertexai_service_account_json" class="neutral_warning" data-i18n="For privacy reasons, your Service Account JSON content will be hidden after you click 'Validate JSON'."> | ||
| 3319 | For privacy reasons, your Service Account JSON content will be hidden after you click 'Validate JSON'. | ||
| 3320 | </div> | ||
| 3321 | <div class="flex-container"> | ||
| 3322 | <button type="button" id="vertexai_validate_service_account" class="menu_button menu_button_icon" data-i18n="Validate JSON">Validate JSON</button> | ||
| 3323 | </div> | ||
| 3324 | </div> | ||
| 3239 | </div> | 3325 | </div> |
| 3240 | <div data-for="api_key_vertexai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3326 | |
| 3241 | For privacy reasons, your API key will be hidden after you reload the page. | 3327 | <!-- Region --> |
| 3328 | <div class="flex-container flexFlowColumn"> | ||
| 3329 | <label for="vertexai_region"> | ||
| 3330 | <span data-i18n="Region"> | ||
| 3331 | Region: | ||
| 3332 | </span> | ||
| 3333 | <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations" target="_blank" rel="noopener noreferrer" title="View available regions and models" data-i18n="[title]View available regions and models" class="notes-link"> | ||
| 3334 | <span class="fa-solid fa-circle-question note-link-span"></span> | ||
| 3335 | </a> | ||
| 3336 | </label> | ||
| 3337 | <input id="vertexai_region" name="vertexai_region" class="text_pole flex1" value="us-central1" type="text" autocomplete="off" placeholder="e.g., global, us-central1, europe-west1, asia-northeast1" list="vertexai_region_suggestions"> | ||
| 3338 | |||
| 3339 | <datalist id="vertexai_region_suggestions"> | ||
| 3340 | <option value="global">global</option> | ||
| 3341 | <option value="us-central1">us-central1</option> | ||
| 3342 | <option value="us-east1">us-east1</option> | ||
| 3343 | <option value="us-east4">us-east4</option> | ||
| 3344 | <option value="us-west1">us-west1</option> | ||
| 3345 | <option value="us-west2">us-west2</option> | ||
| 3346 | <option value="us-west3">us-west3</option> | ||
| 3347 | <option value="us-west4">us-west4</option> | ||
| 3348 | <option value="europe-west1">europe-west1</option> | ||
| 3349 | <option value="europe-west2">europe-west2</option> | ||
| 3350 | <option value="europe-west3">europe-west3</option> | ||
| 3351 | <option value="europe-west4">europe-west4</option> | ||
| 3352 | <option value="europe-west6">europe-west6</option> | ||
| 3353 | <option value="europe-central2">europe-central2</option> | ||
| 3354 | <option value="asia-northeast1">asia-northeast1</option> | ||
| 3355 | <option value="asia-northeast3">asia-northeast3</option> | ||
| 3356 | <option value="asia-southeast1">asia-southeast1</option> | ||
| 3357 | <option value="asia-south1">asia-south1</option> | ||
| 3358 | <option value="australia-southeast1">australia-southeast1</option> | ||
| 3359 | </datalist> | ||
| 3242 | </div> | 3360 | </div> |
| 3361 | |||
| 3362 | <!-- Model Selection --> | ||
| 3243 | <div> | 3363 | <div> |
| 3244 | <h4 data-i18n="Google Model">Google Model</h4> | 3364 | <h4 data-i18n="Google Model">Google Model</h4> |
| 3245 | <select id="model_vertexai_select"> | 3365 | <select id="model_vertexai_select"> |
| 3366 | <!-- data-mode="full" is for models that require a service account --> | ||
| 3246 | <optgroup label="Gemini 2.5"> | 3367 | <optgroup label="Gemini 2.5"> |
| 3368 | <option value="gemini-2.5-pro">gemini-2.5-pro</option> | ||
| 3369 | <option value="gemini-2.5-pro-preview-06-05">gemini-2.5-pro-preview-06-05</option> | ||
| 3247 | <option value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> | 3370 | <option value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> |
| 3248 | <option value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> | 3371 | <option value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> |
| 3372 | <option value="gemini-2.5-pro-exp-03-25" data-mode="full">gemini-2.5-pro-exp-03-25</option> | ||
| 3373 | <option value="gemini-2.5-flash">gemini-2.5-flash</option> | ||
| 3249 | <option value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> | 3374 | <option value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> |
| 3250 | <option value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | 3375 | <option value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> |
| 3376 | <option value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> | ||
| 3251 | </optgroup> | 3377 | </optgroup> |
| 3252 | <optgroup label="Gemini 2.0"> | 3378 | <optgroup label="Gemini 2.0"> |
| 3379 | <option value="gemini-2.0-flash-exp" data-mode="full">gemini-2.0-flash-exp</option> | ||
| 3380 | <option value="gemini-2.0-flash-preview-image-generation" data-mode="full">gemini-2.0-flash-preview-image-generation</option> | ||
| 3381 | <option value="gemini-2.0-flash">gemini-2.0-flash</option> | ||
| 3253 | <option value="gemini-2.0-flash-001">gemini-2.0-flash-001</option> | 3382 | <option value="gemini-2.0-flash-001">gemini-2.0-flash-001</option> |
| 3254 | <option value="gemini-2.0-flash-lite-001">gemini-2.0-flash-lite-001</option> | 3383 | <option value="gemini-2.0-flash-lite-001">gemini-2.0-flash-lite-001</option> |
| 3255 | </optgroup> | 3384 | </optgroup> |
| @@ -3260,10 +3389,10 @@ | |||
| 3260 | <h4 data-i18n="MistralAI API Key">MistralAI API Key</h4> | 3389 | <h4 data-i18n="MistralAI API Key">MistralAI API Key</h4> |
| 3261 | <div class="flex-container"> | 3390 | <div class="flex-container"> |
| 3262 | <input id="api_key_mistralai" name="api_key_mistralai" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3391 | <input id="api_key_mistralai" name="api_key_mistralai" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3263 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_mistralai"></div> | 3392 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_mistralai"></div> |
| 3264 | </div> | 3393 | </div> |
| 3265 | <div data-for="api_key_mistralai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3394 | <div data-for="api_key_mistralai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3266 | For privacy reasons, your API key will be hidden after you reload the page. | 3395 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3267 | </div> | 3396 | </div> |
| 3268 | <div> | 3397 | <div> |
| 3269 | <h4 data-i18n="MistralAI Model">MistralAI Model</h4> | 3398 | <h4 data-i18n="MistralAI Model">MistralAI Model</h4> |
| @@ -3286,6 +3415,8 @@ | |||
| 3286 | <option value="pixtral-12b-latest">pixtral-12b-latest</option> | 3415 | <option value="pixtral-12b-latest">pixtral-12b-latest</option> |
| 3287 | <option value="pixtral-large-latest">pixtral-large-latest</option> | 3416 | <option value="pixtral-large-latest">pixtral-large-latest</option> |
| 3288 | <option value="devstral-small-latest">devstral-small-latest</option> | 3417 | <option value="devstral-small-latest">devstral-small-latest</option> |
| 3418 | <option value="magistral-small-latest">magistral-small-latest</option> | ||
| 3419 | <option value="magistral-medium-latest">magistral-medium-latest</option> | ||
| 3289 | </optgroup> | 3420 | </optgroup> |
| 3290 | <optgroup label="Sub-versions"> | 3421 | <optgroup label="Sub-versions"> |
| 3291 | <option value="open-mistral-nemo-2407">open-mistral-nemo-2407</option> | 3422 | <option value="open-mistral-nemo-2407">open-mistral-nemo-2407</option> |
| @@ -3315,6 +3446,8 @@ | |||
| 3315 | <option value="pixtral-12b-2409">pixtral-12b-2409</option> | 3446 | <option value="pixtral-12b-2409">pixtral-12b-2409</option> |
| 3316 | <option value="pixtral-large-2411">pixtral-large-2411</option> | 3447 | <option value="pixtral-large-2411">pixtral-large-2411</option> |
| 3317 | <option value="devstral-small-2505">devstral-small-2505</option> | 3448 | <option value="devstral-small-2505">devstral-small-2505</option> |
| 3449 | <option value="magistral-small-2506">magistral-small-2506</option> | ||
| 3450 | <option value="magistral-medium-2506">magistral-medium-2506</option> | ||
| 3318 | </optgroup> | 3451 | </optgroup> |
| 3319 | <optgroup id="mistralai_other_models" label="Other"></optgroup> | 3452 | <optgroup id="mistralai_other_models" label="Other"></optgroup> |
| 3320 | </select> | 3453 | </select> |
| @@ -3324,10 +3457,10 @@ | |||
| 3324 | <h4 data-i18n="Groq API Key">Groq API Key</h4> | 3457 | <h4 data-i18n="Groq API Key">Groq API Key</h4> |
| 3325 | <div class="flex-container"> | 3458 | <div class="flex-container"> |
| 3326 | <input id="api_key_groq" name="api_key_groq" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3459 | <input id="api_key_groq" name="api_key_groq" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3327 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_groq"></div> | 3460 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_groq"></div> |
| 3328 | </div> | 3461 | </div> |
| 3329 | <div data-for="api_key_groq" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3462 | <div data-for="api_key_groq" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3330 | For privacy reasons, your API key will be hidden after you reload the page. | 3463 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3331 | </div> | 3464 | </div> |
| 3332 | <h4 data-i18n="Groq Model">Groq Model</h4> | 3465 | <h4 data-i18n="Groq Model">Groq Model</h4> |
| 3333 | <select id="model_groq_select"> | 3466 | <select id="model_groq_select"> |
| @@ -3366,10 +3499,10 @@ | |||
| 3366 | <h4 data-i18n="NanoGPT API Key">NanoGPT API Key</h4> | 3499 | <h4 data-i18n="NanoGPT API Key">NanoGPT API Key</h4> |
| 3367 | <div class="flex-container"> | 3500 | <div class="flex-container"> |
| 3368 | <input id="api_key_nanogpt" name="api_key_nanogpt" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3501 | <input id="api_key_nanogpt" name="api_key_nanogpt" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3369 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_nanogpt"></div> | 3502 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_nanogpt"></div> |
| 3370 | </div> | 3503 | </div> |
| 3371 | <div data-for="api_key_nanogpt" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3504 | <div data-for="api_key_nanogpt" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3372 | For privacy reasons, your API key will be hidden after you reload the page. | 3505 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3373 | </div> | 3506 | </div> |
| 3374 | <div> | 3507 | <div> |
| 3375 | <h4 data-i18n="NanoGPT Model">NanoGPT Model</h4> | 3508 | <h4 data-i18n="NanoGPT Model">NanoGPT Model</h4> |
| @@ -3382,10 +3515,10 @@ | |||
| 3382 | <h4 data-i18n="DeepSeek API Key">DeepSeek API Key</h4> | 3515 | <h4 data-i18n="DeepSeek API Key">DeepSeek API Key</h4> |
| 3383 | <div class="flex-container"> | 3516 | <div class="flex-container"> |
| 3384 | <input id="api_key_deepseek" name="api_key_deepseek" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3517 | <input id="api_key_deepseek" name="api_key_deepseek" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3385 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_deepseek"></div> | 3518 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_deepseek"></div> |
| 3386 | </div> | 3519 | </div> |
| 3387 | <div data-for="api_key_deepseek" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3520 | <div data-for="api_key_deepseek" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3388 | For privacy reasons, your API key will be hidden after you reload the page. | 3521 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3389 | </div> | 3522 | </div> |
| 3390 | <div> | 3523 | <div> |
| 3391 | <h4 data-i18n="DeepSeek Model">DeepSeek Model</h4> | 3524 | <h4 data-i18n="DeepSeek Model">DeepSeek Model</h4> |
| @@ -3400,10 +3533,10 @@ | |||
| 3400 | <h4 data-i18n="Perplexity API Key">Perplexity API Key</h4> | 3533 | <h4 data-i18n="Perplexity API Key">Perplexity API Key</h4> |
| 3401 | <div class="flex-container"> | 3534 | <div class="flex-container"> |
| 3402 | <input id="api_key_perplexity" name="api_key_perplexity" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3535 | <input id="api_key_perplexity" name="api_key_perplexity" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3403 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_perplexity"></div> | 3536 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_perplexity"></div> |
| 3404 | </div> | 3537 | </div> |
| 3405 | <div data-for="api_key_perplexity" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3538 | <div data-for="api_key_perplexity" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3406 | For privacy reasons, your API key will be hidden after you reload the page. | 3539 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3407 | </div> | 3540 | </div> |
| 3408 | <h4 data-i18n="Perplexity Model">Perplexity Model</h4> | 3541 | <h4 data-i18n="Perplexity Model">Perplexity Model</h4> |
| 3409 | <select id="model_perplexity_select"> | 3542 | <select id="model_perplexity_select"> |
| @@ -3431,10 +3564,10 @@ | |||
| 3431 | <h4 data-i18n="Cohere API Key">Cohere API Key</h4> | 3564 | <h4 data-i18n="Cohere API Key">Cohere API Key</h4> |
| 3432 | <div class="flex-container"> | 3565 | <div class="flex-container"> |
| 3433 | <input id="api_key_cohere" name="api_key_cohere" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3566 | <input id="api_key_cohere" name="api_key_cohere" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3434 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_cohere"></div> | 3567 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_cohere"></div> |
| 3435 | </div> | 3568 | </div> |
| 3436 | <div data-for="api_key_cohere" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3569 | <div data-for="api_key_cohere" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3437 | For privacy reasons, your API key will be hidden after you reload the page. | 3570 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3438 | </div> | 3571 | </div> |
| 3439 | <div> | 3572 | <div> |
| 3440 | <h4 data-i18n="Cohere Model">Cohere Model</h4> | 3573 | <h4 data-i18n="Cohere Model">Cohere Model</h4> |
| @@ -3470,7 +3603,7 @@ | |||
| 3470 | <div> | 3603 | <div> |
| 3471 | <small> | 3604 | <small> |
| 3472 | <span data-i18n="Doesn't work? Try adding">Doesn't work? Try adding</span> <code>/v1</code> <span data-i18n="at the end!">at the end!</span> | 3605 | <span data-i18n="Doesn't work? Try adding">Doesn't work? Try adding</span> <code>/v1</code> <span data-i18n="at the end!">at the end!</span> |
| 3473 | <code>/chat/completions</code> <b data-i18n="suffix will be added automatically.">suffix will be added automatically.</b> | 3606 | <b data-i18n="completions note prefix"></b><code>/chat/completions</code> <b data-i18n="suffix will be added automatically.">suffix will be added automatically.</b> |
| 3474 | </small> | 3607 | </small> |
| 3475 | </div> | 3608 | </div> |
| 3476 | <h4> | 3609 | <h4> |
| @@ -3479,10 +3612,10 @@ | |||
| 3479 | </h4> | 3612 | </h4> |
| 3480 | <div class="flex-container"> | 3613 | <div class="flex-container"> |
| 3481 | <input id="api_key_custom" name="api_key_custom" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3614 | <input id="api_key_custom" name="api_key_custom" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3482 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_custom"></div> | 3615 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_custom"></div> |
| 3483 | </div> | 3616 | </div> |
| 3484 | <div data-for="api_key_custom" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3617 | <div data-for="api_key_custom" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3485 | For privacy reasons, your API key will be hidden after you reload the page. | 3618 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3486 | </div> | 3619 | </div> |
| 3487 | <h4 data-i18n="Enter a Model ID">Enter a Model ID</h4> | 3620 | <h4 data-i18n="Enter a Model ID">Enter a Model ID</h4> |
| 3488 | <div class="flex-container"> | 3621 | <div class="flex-container"> |
| @@ -3502,10 +3635,10 @@ | |||
| 3502 | </h4> | 3635 | </h4> |
| 3503 | <div class="flex-container"> | 3636 | <div class="flex-container"> |
| 3504 | <input id="api_key_01ai" name="api_key_01ai" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3637 | <input id="api_key_01ai" name="api_key_01ai" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3505 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_01ai"></div> | 3638 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_01ai"></div> |
| 3506 | </div> | 3639 | </div> |
| 3507 | <div data-for="api_key_01ai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3640 | <div data-for="api_key_01ai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3508 | For privacy reasons, your API key will be hidden after you reload the page. | 3641 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3509 | </div> | 3642 | </div> |
| 3510 | <h4 data-i18n="01.AI Model">01.AI Model</h4> | 3643 | <h4 data-i18n="01.AI Model">01.AI Model</h4> |
| 3511 | <select id="model_01ai_select"> | 3644 | <select id="model_01ai_select"> |
| @@ -3519,10 +3652,10 @@ | |||
| 3519 | </h4> | 3652 | </h4> |
| 3520 | <div class="flex-container"> | 3653 | <div class="flex-container"> |
| 3521 | <input id="api_key_xai" name="api_key_xai" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3654 | <input id="api_key_xai" name="api_key_xai" class="text_pole flex1" value="" type="text" autocomplete="off"> |
| 3522 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_xai"></div> | 3655 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_xai"></div> |
| 3523 | </div> | 3656 | </div> |
| 3524 | <div data-for="api_key_xai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | 3657 | <div data-for="api_key_xai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> |
| 3525 | For privacy reasons, your API key will be hidden after you reload the page. | 3658 | For privacy reasons, your API key will be hidden after you click 'Connect'. |
| 3526 | </div> | 3659 | </div> |
| 3527 | <h4 data-i18n="xAI Model">xAI Model</h4> | 3660 | <h4 data-i18n="xAI Model">xAI Model</h4> |
| 3528 | <select id="model_xai_select"> | 3661 | <select id="model_xai_select"> |
| @@ -3536,6 +3669,21 @@ | |||
| 3536 | <option value="grok-beta">grok-beta</option> | 3669 | <option value="grok-beta">grok-beta</option> |
| 3537 | </select> | 3670 | </select> |
| 3538 | </div> | 3671 | </div> |
| 3672 | <div id="aimlapi_form" data-source="aimlapi"> | ||
| 3673 | <h4> | ||
| 3674 | <span>AI/ML API Key</span> | ||
| 3675 | </h4> | ||
| 3676 | <div class="flex-container"> | ||
| 3677 | <input id="api_key_aimlapi" name="api_key_aimlapi" class="text_pole flex1" value="" type="text" autocomplete="off"> | ||
| 3678 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_aimlapi"></div> | ||
| 3679 | </div> | ||
| 3680 | <div data-for="api_key_aimlapi" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> | ||
| 3681 | For privacy reasons, your API key will be hidden after you click 'Connect'. | ||
| 3682 | </div> | ||
| 3683 | <h4>AI/ML Model</h4> | ||
| 3684 | <select id="model_aimlapi_select"> | ||
| 3685 | </select> | ||
| 3686 | </div> | ||
| 3539 | <div id="pollinations_form" data-source="pollinations"> | 3687 | <div id="pollinations_form" data-source="pollinations"> |
| 3540 | <h4 data-i18n="Pollinations Model">Pollinations Model</h4> | 3688 | <h4 data-i18n="Pollinations Model">Pollinations Model</h4> |
| 3541 | <select id="model_pollinations_select"> | 3689 | <select id="model_pollinations_select"> |
| @@ -3562,10 +3710,17 @@ | |||
| 3562 | </h4> | 3710 | </h4> |
| 3563 | <select id="custom_prompt_post_processing" class="text_pole" title="Applies additional processing to the prompt before sending it to the API." data-i18n="[title]Applies additional processing to the prompt before sending it to the API."> | 3711 | <select id="custom_prompt_post_processing" class="text_pole" title="Applies additional processing to the prompt before sending it to the API." data-i18n="[title]Applies additional processing to the prompt before sending it to the API."> |
| 3564 | <option data-i18n="prompt_post_processing_none" value="">None</option> | 3712 | <option data-i18n="prompt_post_processing_none" value="">None</option> |
| 3565 | <option data-i18n="prompt_post_processing_merge" value="merge">Merge consecutive roles</option> | 3713 | <optgroup label="With Tools"> |
| 3566 | <option data-i18n="prompt_post_processing_semi" value="semi">Semi-strict (alternating roles)</option> | 3714 | <option data-i18n="prompt_post_processing_merge_tools" value="merge_tools">Merge consecutive roles (with tools)</option> |
| 3567 | <option data-i18n="prompt_post_processing_strict" value="strict">Strict (user first, alternating roles)</option> | 3715 | <option data-i18n="prompt_post_processing_semi_tools" value="semi_tools">Semi-strict (alternating roles; with tools)</option> |
| 3568 | <option data-i18n="prompt_post_processing_single" value="single">Single user message</option> | 3716 | <option data-i18n="prompt_post_processing_strict_tools" value="strict_tools">Strict (user first, alternating roles; with tools)</option> |
| 3717 | </optgroup> | ||
| 3718 | <optgroup label="No Tools"> | ||
| 3719 | <option data-i18n="prompt_post_processing_merge" value="merge">Merge consecutive roles (no tools)</option> | ||
| 3720 | <option data-i18n="prompt_post_processing_semi" value="semi">Semi-strict (alternating roles; no tools)</option> | ||
| 3721 | <option data-i18n="prompt_post_processing_strict" value="strict">Strict (user first, alternating roles; no tools)</option> | ||
| 3722 | <option data-i18n="prompt_post_processing_single" value="single">Single user message (no tools)</option> | ||
| 3723 | </optgroup> | ||
| 3569 | </select> | 3724 | </select> |
| 3570 | </div> | 3725 | </div> |
| 3571 | <div class="flex-container flex"> | 3726 | <div class="flex-container flex"> |
| @@ -3585,7 +3740,9 @@ | |||
| 3585 | <label for="auto-connect-checkbox" class="checkbox_label"><input id="auto-connect-checkbox" type="checkbox" /> | 3740 | <label for="auto-connect-checkbox" class="checkbox_label"><input id="auto-connect-checkbox" type="checkbox" /> |
| 3586 | <span data-i18n="Auto-connect to Last Server">Auto-connect to Last Server</span> | 3741 | <span data-i18n="Auto-connect to Last Server">Auto-connect to Last Server</span> |
| 3587 | </label> | 3742 | </label> |
| 3588 | <a id="viewSecrets" href="javascript:void(0);" data-i18n="[missing_key_text]Missing key;[key_saved_text]Key saved" missing_key_text="❌ Missing key" key_saved_text="✔️ Key saved"><span data-i18n="View hidden API keys">View hidden API keys</span></a> | 3743 | <a id="viewSecrets" href="javascript:void(0);" data-i18n="[missing_key_text]Missing key;[key_saved_text]Key saved" missing_key_text="❌ Missing key" key_saved_text="✔️ Key saved"> |
| 3744 | <span data-i18n="View hidden API keys">View hidden API keys</span> | ||
| 3745 | </a> | ||
| 3589 | </div> | 3746 | </div> |
| 3590 | </div> | 3747 | </div> |
| 3591 | </div> | 3748 | </div> |
| @@ -3725,11 +3882,11 @@ | |||
| 3725 | <input id="instruct_derived" type="checkbox" style="display:none;" /> | 3882 | <input id="instruct_derived" type="checkbox" style="display:none;" /> |
| 3726 | <small><i class="fa-solid fa-bolt menu_button margin0"></i></small> | 3883 | <small><i class="fa-solid fa-bolt menu_button margin0"></i></small> |
| 3727 | </label> | 3884 | </label> |
| 3728 | <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"> | 3885 | <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"> |
| 3729 | <input id="instruct_bind_to_context" type="checkbox" style="display:none;" /> | 3886 | <input id="instruct_bind_to_context" type="checkbox" style="display:none;" /> |
| 3730 | <small><i class="fa-solid fa-link menu_button margin0"></i></small> | 3887 | <small><i class="fa-solid fa-link menu_button margin0"></i></small> |
| 3731 | </label> | 3888 | </label> |
| 3732 | <label id="instruct_enabled_label"for="instruct_enabled" class="checkbox_label flex1" title="Enable Instruct Mode" data-i18n="[title]instruct_enabled"> | 3889 | <label id="instruct_enabled_label" for="instruct_enabled" class="checkbox_label flex1" title="Enable Instruct Mode" data-i18n="[title]instruct_enabled"> |
| 3733 | <input id="instruct_enabled" type="checkbox" style="display:none;" /> | 3890 | <input id="instruct_enabled" type="checkbox" style="display:none;" /> |
| 3734 | <small><i class="fa-solid fa-power-off menu_button togglable margin0"></i></small> | 3891 | <small><i class="fa-solid fa-power-off menu_button togglable margin0"></i></small> |
| 3735 | </label> | 3892 | </label> |
| @@ -4042,7 +4199,7 @@ | |||
| 4042 | </small> | 4199 | </small> |
| 4043 | </label> | 4200 | </label> |
| 4044 | <div class="flex1 flex-container alignItemsBaseline" title="Maximum number of reasoning blocks to be added per prompt, counting from the last message." data-i18n="[title]reasoning_max_additions"> | 4201 | <div class="flex1 flex-container alignItemsBaseline" title="Maximum number of reasoning blocks to be added per prompt, counting from the last message." data-i18n="[title]reasoning_max_additions"> |
| 4045 | <input id="reasoning_max_additions" class="text_pole textarea_compact widthUnset" type="number" min="0" max="999"></textarea> | 4202 | <input id="reasoning_max_additions" class="text_pole textarea_compact widthUnset" type="number" min="0" max="999" /> |
| 4046 | <small data-i18n="Max">Max</small> | 4203 | <small data-i18n="Max">Max</small> |
| 4047 | </div> | 4204 | </div> |
| 4048 | </div> | 4205 | </div> |
| @@ -4173,8 +4330,8 @@ | |||
| 4173 | <small> | 4330 | <small> |
| 4174 | <span data-i18n="Scan Depth">Scan Depth</span> | 4331 | <span data-i18n="Scan Depth">Scan Depth</span> |
| 4175 | </small> | 4332 | </small> |
| 4176 | <input class="neo-range-slider" type="range" id="world_info_depth" name="world_info_depth" min="0" max="100" step="1"> | 4333 | <input class="neo-range-slider" type="range" id="world_info_depth" name="world_info_depth" min="0" max="1000" step="1"> |
| 4177 | <input class="neo-range-input" type="number" min="0" max="100" step="1" data-for="world_info_depth" id="world_info_depth_counter"> | 4334 | <input class="neo-range-input" type="number" min="0" max="1000" step="1" data-for="world_info_depth" id="world_info_depth_counter"> |
| 4178 | </div> | 4335 | </div> |
| 4179 | 4336 | ||
| 4180 | <div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p"> | 4337 | <div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p"> |
| @@ -4190,8 +4347,8 @@ | |||
| 4190 | <span data-i18n="Budget Cap">Budget Cap</span> | 4347 | <span data-i18n="Budget Cap">Budget Cap</span> |
| 4191 | <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title](0 = disabled)" title="(0 = disabled)"></div> | 4348 | <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title](0 = disabled)" title="(0 = disabled)"></div> |
| 4192 | </small> | 4349 | </small> |
| 4193 | <input class="neo-range-slider" type="range" id="world_info_budget_cap" name="world_info_budget_cap" min="0" max="8192" step="1"> | 4350 | <input class="neo-range-slider" type="range" id="world_info_budget_cap" name="world_info_budget_cap" min="0" max="65536" step="1"> |
| 4194 | <input class="neo-range-input" type="number" min="0" max="8192" step="1" data-for="world_info_budget_cap" id="world_info_budget_cap_counter"> | 4351 | <input class="neo-range-input" type="number" min="0" max="65536" step="1" data-for="world_info_budget_cap" id="world_info_budget_cap_counter"> |
| 4195 | </div> | 4352 | </div> |
| 4196 | 4353 | ||
| 4197 | <div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" title="Scan chronologically until reached min entries or token budget." data-i18n="[title]Scan chronologically until reached min entries or token budget."> | 4354 | <div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" title="Scan chronologically until reached min entries or token budget." data-i18n="[title]Scan chronologically until reached min entries or token budget."> |
| @@ -4643,6 +4800,10 @@ | |||
| 4643 | <input id="never_resize_avatars" type="checkbox" /> | 4800 | <input id="never_resize_avatars" type="checkbox" /> |
| 4644 | <small data-i18n="Never resize avatars">Never resize avatars</small> | 4801 | <small data-i18n="Never resize avatars">Never resize avatars</small> |
| 4645 | </label> | 4802 | </label> |
| 4803 | <label data-i18n="[title]Allow animations for WEBP backgrounds. This is only a change for the selection menu." for="background_thumbnails_animation" class="checkbox_label" title="Allow animations for WEBP backgrounds. This is only a change for the selection menu."> | ||
| 4804 | <input id="background_thumbnails_animation" type="checkbox" /> | ||
| 4805 | <small data-i18n="Animated background thumbnails">Animated background thumbnails</small> | ||
| 4806 | </label> | ||
| 4646 | <label class="checkbox_label" for="show_card_avatar_urls" title="Show actual file names on the disk, in the characters list display only." data-i18n="[title]Show actual file names on the disk, in the characters list display only"> | 4807 | <label class="checkbox_label" for="show_card_avatar_urls" title="Show actual file names on the disk, in the characters list display only." data-i18n="[title]Show actual file names on the disk, in the characters list display only"> |
| 4647 | <input id="show_card_avatar_urls" type="checkbox" /> | 4808 | <input id="show_card_avatar_urls" type="checkbox" /> |
| 4648 | <small data-i18n="Show avatar filenames">Show avatar filenames</small> | 4809 | <small data-i18n="Show avatar filenames">Show avatar filenames</small> |
| @@ -4656,13 +4817,16 @@ | |||
| 4656 | 4817 | ||
| 4657 | <div name="MiscellaneousToggles"> | 4818 | <div name="MiscellaneousToggles"> |
| 4658 | <h4><span data-i18n="Miscellaneous">Miscellaneous</span></h4> | 4819 | <h4><span data-i18n="Miscellaneous">Miscellaneous</span></h4> |
| 4659 | <div class="flex-container"> | 4820 | <div class="flex-container flexGap2"> |
| 4660 | <div id="reload_chat" class="menu_button whitespacenowrap" data-i18n="[title]Reload and redraw the currently open chat" title="Reload and redraw the currently open chat."> | 4821 | <div id="reload_chat" class="menu_button whitespacenowrap" data-i18n="[title]Reload and redraw the currently open chat" title="Reload and redraw the currently open chat."> |
| 4661 | <small data-i18n="Reload Chat">Reload Chat</small> | 4822 | <small data-i18n="Reload Chat">Reload Chat</small> |
| 4662 | </div> | 4823 | </div> |
| 4663 | <div id="debug_menu" class="menu_button whitespacenowrap"> | 4824 | <div id="debug_menu" class="menu_button whitespacenowrap"> |
| 4664 | <small data-i18n="Debug Menu">Debug Menu</small> | 4825 | <small data-i18n="Debug Menu">Debug Menu</small> |
| 4665 | </div> | 4826 | </div> |
| 4827 | <div id="data_maid_button" class="menu_button whitespacenowrap" title="Find and delete backups, unused chats, files, images, etc." data-i18n="[title]Find and delete backups, unused chats, files, images, etc."> | ||
| 4828 | <small data-i18n="Clean-Up">Clean-Up</small> | ||
| 4829 | </div> | ||
| 4666 | </div> | 4830 | </div> |
| 4667 | <label class="checkbox_label flexWrap" for="smooth_streaming"> | 4831 | <label class="checkbox_label flexWrap" for="smooth_streaming"> |
| 4668 | <input id="smooth_streaming" type="checkbox" /> | 4832 | <input id="smooth_streaming" type="checkbox" /> |
| @@ -4942,6 +5106,14 @@ | |||
| 4942 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | 5106 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> |
| 4943 | </div> | 5107 | </div> |
| 4944 | <div class="inline-drawer-content"> | 5108 | <div class="inline-drawer-content"> |
| 5109 | <label for="stscript_autocomplete_state"> | ||
| 5110 | <small data-i18n="Visibility">Visibility</small> | ||
| 5111 | </label> | ||
| 5112 | <select id="stscript_autocomplete_state"> | ||
| 5113 | <option value="0" data-i18n="Don't show">Don't show</option> | ||
| 5114 | <option value="1" data-i18n="Input length > 1">Input length > 1</option> | ||
| 5115 | <option value="2" data-i18n="Always show">Always show</option> | ||
| 5116 | </select> | ||
| 4945 | <label class="checkbox_label" for="stscript_autocomplete_autoHide"> | 5117 | <label class="checkbox_label" for="stscript_autocomplete_autoHide"> |
| 4946 | <input id="stscript_autocomplete_autoHide" type="checkbox" /> | 5118 | <input id="stscript_autocomplete_autoHide" type="checkbox" /> |
| 4947 | <small data-i18n="Automatically hide details"> | 5119 | <small data-i18n="Automatically hide details"> |
| @@ -5177,7 +5349,7 @@ | |||
| 5177 | <div class="flex-container wide100p alignitemscenter spaceBetween flexNoGap"> | 5349 | <div class="flex-container wide100p alignitemscenter spaceBetween flexNoGap"> |
| 5178 | <div class="flex-container alignItemsBaseline wide100p"> | 5350 | <div class="flex-container alignItemsBaseline wide100p"> |
| 5179 | <div class="flex1 flex-container alignItemsBaseline"> | 5351 | <div class="flex1 flex-container alignItemsBaseline"> |
| 5180 | <h3 class="margin0" > | 5352 | <h3 class="margin0"> |
| 5181 | <span data-i18n="Persona Management">Persona Management</span> | 5353 | <span data-i18n="Persona Management">Persona Management</span> |
| 5182 | <a href="https://docs.sillytavern.app/usage/core-concepts/personas/" target="_blank"> | 5354 | <a href="https://docs.sillytavern.app/usage/core-concepts/personas/" target="_blank"> |
| 5183 | <span class="fa-solid fa-circle-question note-link-span"></span> | 5355 | <span class="fa-solid fa-circle-question note-link-span"></span> |
| @@ -5348,10 +5520,12 @@ | |||
| 5348 | <div class="right_menu_button fa-solid fa-list-ul" id="rm_button_characters" title="Select/Create Characters" data-i18n="[title]Select/Create Characters"></div> | 5520 | <div class="right_menu_button fa-solid fa-list-ul" id="rm_button_characters" title="Select/Create Characters" data-i18n="[title]Select/Create Characters"></div> |
| 5349 | </div> | 5521 | </div> |
| 5350 | <div id="HotSwapWrapper" class="alignitemscenter flex-container margin0auto wide100p"> | 5522 | <div id="HotSwapWrapper" class="alignitemscenter flex-container margin0auto wide100p"> |
| 5351 | <div class="hotswap avatars_inline scroll-reset-container expander" data-i18n="[no_favs]Favorite characters to add them to HotSwaps" no_favs="Favorite characters to add them to HotSwaps"></div> | 5523 | <div class="hotswap avatars_inline scroll-reset-container expander" data-i18n="[no_favs]Favorite characters to add them to HotSwaps" no_favs="Favorite characters to add them to HotSwaps"> |
| 5524 | </div> | ||
| 5525 | <hr class="wide100p"> | ||
| 5352 | </div> | 5526 | </div> |
| 5353 | </div> | 5527 | </div> |
| 5354 | <hr> | 5528 | |
| 5355 | <!-- this div structure must be preserved until group peeking can adjust --> | 5529 | <!-- this div structure must be preserved until group peeking can adjust --> |
| 5356 | <div id="rm_PinAndTabs"> | 5530 | <div id="rm_PinAndTabs"> |
| 5357 | <div id="right-nav-panel-tabs" class=""> | 5531 | <div id="right-nav-panel-tabs" class=""> |
| @@ -5376,340 +5550,343 @@ | |||
| 5376 | </div> | 5550 | </div> |
| 5377 | </div> | 5551 | </div> |
| 5378 | <!-- end group peeking cope structure--> | 5552 | <!-- end group peeking cope structure--> |
| 5379 | <div name="Solo Char Create/Edit Panel" id="rm_ch_create_block" class="right_menu flex-container flexFlowColumn" style="display: none;"> | 5553 | |
| 5380 | <form id="form_create" action="javascript:void(null);" method="post" enctype="multipart/form-data"> | 5554 | <div class="scrollableInner"> |
| 5381 | <div id="avatar-and-name-block"> | 5555 | <div name="Solo Char Create/Edit Panel" id="rm_ch_create_block" class="right_menu flex-container flexFlowColumn" style="display: none;"> |
| 5382 | <div id="name_div"> | 5556 | <form id="form_create" action="javascript:void(null);" method="post" enctype="multipart/form-data"> |
| 5383 | <input id="character_name_pole" name="ch_name" class="text_pole" data-i18n="[placeholder]Name this character" placeholder="Name this character" value="" autocomplete="off"> | 5557 | <div id="avatar-and-name-block"> |
| 5384 | <div class="extension_token_counter"> | 5558 | <div id="name_div"> |
| 5385 | <span data-i18n="extension_token_counter">Tokens:</span> <span data-token-counter="character_name_pole" data-token-permanent="true">counting...</span> | 5559 | <input id="character_name_pole" name="ch_name" class="text_pole" data-i18n="[placeholder]Name this character" placeholder="Name this character" value="" autocomplete="off"> |
| 5386 | </div> | 5560 | <div class="extension_token_counter"> |
| 5387 | </div> | 5561 | <span data-i18n="extension_token_counter">Tokens:</span> <span data-token-counter="character_name_pole" data-token-permanent="true">counting...</span> |
| 5388 | <div class="flex-container flexFlowColumn expander flexNoGap"> | 5562 | </div> |
| 5389 | <div id="avatar_div" class="avatar_div buttons_block alignitemsflexstart justifySpaceBetween flexnowrap"> | 5563 | </div> |
| 5390 | <label id="avatar_div_div" class="add_avatar avatar" for="add_avatar_button" title="Click to select a new avatar for this character" data-i18n="[title]Click to select a new avatar for this character"> | 5564 | <div class="flex-container flexFlowColumn expander flexNoGap"> |
| 5391 | <img id="avatar_load_preview" src="img/ai4.png" alt="avatar"> | 5565 | <div id="avatar_div" class="avatar_div buttons_block alignitemsflexstart justifySpaceBetween flexnowrap"> |
| 5392 | <input hidden type="file" id="add_avatar_button" name="avatar" accept="image/*"> | 5566 | <label id="avatar_div_div" class="add_avatar avatar" for="add_avatar_button" title="Click to select a new avatar for this character" data-i18n="[title]Click to select a new avatar for this character"> |
| 5393 | </label> | 5567 | <img id="avatar_load_preview" src="img/ai4.png" alt="avatar"> |
| 5394 | <div class="flex-container" id="avatar_controls"> | 5568 | <input hidden type="file" id="add_avatar_button" name="avatar" accept="image/*"> |
| 5395 | <div class="form_create_bottom_buttons_block buttons_block"> | 5569 | </label> |
| 5396 | <div id="rm_button_back" class="menu_button fa-solid fa-left-long "></div> | 5570 | <div class="flex-container" id="avatar_controls"> |
| 5397 | <!-- <div id="renameCharButton" class="menu_button fa-solid fa-user-pen" title="Rename Character"></div> --> | 5571 | <div class="form_create_bottom_buttons_block buttons_block"> |
| 5398 | <div id="favorite_button" class="menu_button fa-solid fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div> | 5572 | <div id="rm_button_back" class="menu_button fa-solid fa-left-long "></div> |
| 5399 | <input type="hidden" id="fav_checkbox" name="fav" /> | 5573 | <!-- <div id="renameCharButton" class="menu_button fa-solid fa-user-pen" title="Rename Character"></div> --> |
| 5400 | <div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions" data-i18n="[title]Advanced Definition"></div> | 5574 | <div id="favorite_button" class="menu_button fa-solid fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div> |
| 5401 | <div id="world_button" class="menu_button fa-solid fa-globe" title="Character Lore Click to load Shift-click to open 'Link to World Info' popup" data-i18n="[title]world_button_title"></div> | 5575 | <input type="hidden" id="fav_checkbox" name="fav" /> |
| 5402 | <div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore Alt+Click to open the lorebook" data-i18n="[title]Chat Lore Alt+Click to open the lorebook"></div> | 5576 | <div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions" data-i18n="[title]Advanced Definition"></div> |
| 5403 | <div id="char_connections_button" class="menu_button fa-solid fa-face-smile" title="Connected Personas" data-i18n="[title]Connected Personas"></div> | 5577 | <div id="world_button" class="menu_button fa-solid fa-globe" title="Character Lore Click to load Shift-click to open 'Link to World Info' popup" data-i18n="[title]world_button_title"></div> |
| 5404 | <div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download" data-i18n="[title]Export and Download"></div> | 5578 | <div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore Alt+Click to open the lorebook" data-i18n="[title]Chat Lore Alt+Click to open the lorebook"></div> |
| 5405 | <!-- <div id="set_chat_scenario" class="menu_button fa-solid fa-scroll" title="Set a chat scenario override"></div> --> | 5579 | <div id="char_connections_button" class="menu_button fa-solid fa-face-smile" title="Connected Personas" data-i18n="[title]Connected Personas"></div> |
| 5406 | <!-- <div id="set_character_world" class="menu_button fa-solid fa-globe" title="Set a character World Info / Lorebook"></div> --> | 5580 | <div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download" data-i18n="[title]Export and Download"></div> |
| 5407 | <div id="dupe_button" class="menu_button fa-solid fa-clone " title="Duplicate Character" data-i18n="[title]Duplicate Character"></div> | 5581 | <!-- <div id="set_chat_scenario" class="menu_button fa-solid fa-scroll" title="Set a chat scenario override"></div> --> |
| 5408 | <label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character" data-i18n="[title]Create Character"> | 5582 | <!-- <div id="set_character_world" class="menu_button fa-solid fa-globe" title="Set a character World Info / Lorebook"></div> --> |
| 5409 | <input type="submit" id="create_button" name="create_button"> | 5583 | <div id="dupe_button" class="menu_button fa-solid fa-clone " title="Duplicate Character" data-i18n="[title]Duplicate Character"></div> |
| 5410 | </label> | 5584 | <label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character" data-i18n="[title]Create Character"> |
| 5411 | <div id="delete_button" class="menu_button fa-solid fa-skull red_button" title="Delete Character" data-i18n="[title]Delete Character"></div> | 5585 | <input type="submit" id="create_button" name="create_button"> |
| 5412 | </div> | 5586 | </label> |
| 5413 | <label class="flex1 height100p" for="char-management-dropdown"> | 5587 | <div id="delete_button" class="menu_button fa-solid fa-skull red_button" title="Delete Character" data-i18n="[title]Delete Character"></div> |
| 5414 | <select id="char-management-dropdown" class="text_pole"> | 5588 | </div> |
| 5415 | <option value="default" disabled selected data-i18n="More...">More...</option> | 5589 | <label class="flex1 height100p" for="char-management-dropdown"> |
| 5416 | <option id="set_character_world" data-i18n="Link to World Info"> | 5590 | <select id="char-management-dropdown" class="text_pole"> |
| 5417 | Link to World Info | 5591 | <option value="default" disabled selected data-i18n="More...">More...</option> |
| 5418 | </option> | 5592 | <option id="set_character_world" data-i18n="Link to World Info"> |
| 5419 | <option id="import_character_info" data-i18n="Import Card Lore"> | 5593 | Link to World Info |
| 5420 | Import Card Lore | ||
| 5421 | </option> | ||
| 5422 | <option id="set_chat_scenario" data-i18n="Scenario Override"> | ||
| 5423 | Scenario Override | ||
| 5424 | </option> | ||
| 5425 | <option id="convert_to_persona" data-i18n="Convert to Persona"> | ||
| 5426 | Convert to Persona | ||
| 5427 | </option> | ||
| 5428 | <option id="renameCharButton" data-i18n="Rename"> | ||
| 5429 | Rename | ||
| 5430 | </option> | ||
| 5431 | <option id="character_source" data-i18n="Link to Source"> | ||
| 5432 | Link to Source | ||
| 5433 | </option> | ||
| 5434 | <option id="replace_update" data-i18n="Replace / Update"> | ||
| 5435 | Replace / Update | ||
| 5436 | </option> | ||
| 5437 | <option id="import_tags" data-i18n="Import Tags"> | ||
| 5438 | Import Tags | ||
| 5439 | </option> | ||
| 5440 | <option id="set_as_assistant" data-i18n="Set / Unset as Welcome Page Assistant"> | ||
| 5441 | Set / Unset as Welcome Page Assistant | ||
| 5442 | </option> | ||
| 5443 | <!--<option id="dupe_button"> | ||
| 5444 | Duplicate | ||
| 5445 | </option> | 5594 | </option> |
| 5446 | <option id="export_button"> | 5595 | <option id="import_character_info" data-i18n="Import Card Lore"> |
| 5447 | Export | 5596 | Import Card Lore |
| 5448 | </option> | 5597 | </option> |
| 5449 | <option id="delete_button"> | 5598 | <option id="set_chat_scenario" data-i18n="Scenario Override"> |
| 5450 | Delete | 5599 | Scenario Override |
| 5451 | </option>--> | 5600 | </option> |
| 5452 | </select> | 5601 | <option id="convert_to_persona" data-i18n="Convert to Persona"> |
| 5453 | </label> | 5602 | Convert to Persona |
| 5603 | </option> | ||
| 5604 | <option id="renameCharButton" data-i18n="Rename"> | ||
| 5605 | Rename | ||
| 5606 | </option> | ||
| 5607 | <option id="character_source" data-i18n="Link to Source"> | ||
| 5608 | Link to Source | ||
| 5609 | </option> | ||
| 5610 | <option id="replace_update" data-i18n="Replace / Update"> | ||
| 5611 | Replace / Update | ||
| 5612 | </option> | ||
| 5613 | <option id="import_tags" data-i18n="Import Tags"> | ||
| 5614 | Import Tags | ||
| 5615 | </option> | ||
| 5616 | <option id="set_as_assistant" data-i18n="Set / Unset as Welcome Page Assistant"> | ||
| 5617 | Set / Unset as Welcome Page Assistant | ||
| 5618 | </option> | ||
| 5619 | <!--<option id="dupe_button"> | ||
| 5620 | Duplicate | ||
| 5621 | </option> | ||
| 5622 | <option id="export_button"> | ||
| 5623 | Export | ||
| 5624 | </option> | ||
| 5625 | <option id="delete_button"> | ||
| 5626 | Delete | ||
| 5627 | </option>--> | ||
| 5628 | </select> | ||
| 5629 | </label> | ||
| 5630 | </div> | ||
| 5454 | </div> | 5631 | </div> |
| 5455 | </div> | 5632 | <div id="tags_div"> |
| 5456 | <div id="tags_div"> | 5633 | <div class="tag_controls"> |
| 5457 | <div class="tag_controls"> | 5634 | <input id="tagInput" class="text_pole textarea_compact tag_input wide100p margin0" data-i18n="[placeholder]Search / Create Tags" placeholder="Search / Create tags" /> |
| 5458 | <input id="tagInput" class="text_pole textarea_compact tag_input wide100p margin0" data-i18n="[placeholder]Search / Create Tags" placeholder="Search / Create tags" /> | 5635 | <div class="tags_view menu_button fa-solid fa-tags" title="View all tags" data-i18n="[title]View all tags"></div> |
| 5459 | <div class="tags_view menu_button fa-solid fa-tags" title="View all tags" data-i18n="[title]View all tags"></div> | 5636 | </div> |
| 5637 | <div id="tagList" class="tags"></div> | ||
| 5460 | </div> | 5638 | </div> |
| 5461 | <div id="tagList" class="tags"></div> | ||
| 5462 | </div> | 5639 | </div> |
| 5463 | </div> | 5640 | </div> |
| 5464 | </div> | ||
| 5465 | <hr> | ||
| 5466 | <div id="spoiler_free_desc" class="flex-container flexFlowColumn flex1 flexNoGap"> | ||
| 5467 | <div id="creators_notes_div" class="title_restorable flexGap5"> | ||
| 5468 | <span class="flex1" data-i18n="Creator's Notes">Creator's Notes</span> | ||
| 5469 | <small id="creators_note_desc_hidden" data-i18n="Character details are hidden.">Character details are hidden.</small> | ||
| 5470 | <div id="creators_note_styles_button" class="margin0 menu_button fa-solid fa-palette fa-fw" title="Allow / Forbid the use of global styles for this character." data-i18n="[title]Allow / Forbid the use of global styles for this character."></div> | ||
| 5471 | <div id="spoiler_free_desc_button" class="margin0 menu_button fa-solid fa-eye fa-fw" title="Show / Hide Description and First Message" data-i18n="[title]Show / Hide Description and First Message"></div> | ||
| 5472 | </div> | ||
| 5473 | <div id="creator_notes_spoiler" class="flex1"></div> | ||
| 5474 | <!-- A button to show / hide description_div and description_textarea and first_message_div and firstmessage_textarea--> | ||
| 5475 | </div> | ||
| 5476 | <div id="descriptionWrapper" class="flex-container flexFlowColumn flex1"> | ||
| 5477 | <hr> | 5641 | <hr> |
| 5478 | <div id="description_div" class="title_restorable"> | 5642 | <div id="spoiler_free_desc" class="flex-container flexFlowColumn flex1 flexNoGap"> |
| 5479 | <div class="flex-container alignitemscenter"> | 5643 | <div id="creators_notes_div" class="title_restorable flexGap5"> |
| 5480 | <span data-i18n="Character Description" class="mdhotkey_location">Description</span> | 5644 | <span class="flex1" data-i18n="Creator's Notes">Creator's Notes</span> |
| 5481 | <i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="description_textarea" title="Expand the editor" data-i18n="[title]Expand the editor"></i> | 5645 | <small id="creators_note_desc_hidden" data-i18n="Character details are hidden.">Character details are hidden.</small> |
| 5482 | <a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#character-description" class="notes-link" target="_blank"> | 5646 | <div id="creators_note_styles_button" class="margin0 menu_button fa-solid fa-palette fa-fw" title="Allow / Forbid the use of global styles for this character." data-i18n="[title]Allow / Forbid the use of global styles for this character."></div> |
| 5483 | <span class="fa-solid fa-circle-question note-link-span"></span> | 5647 | <div id="spoiler_free_desc_button" class="margin0 menu_button fa-solid fa-eye fa-fw" title="Show / Hide Description and First Message" data-i18n="[title]Show / Hide Description and First Message"></div> |
| 5484 | </a> | ||
| 5485 | </div> | 5648 | </div> |
| 5486 | <div id="character_open_media_overrides" class="menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this character." data-i18n="[title]Click to allow/forbid the use of external media for this character."> | 5649 | <div id="creator_notes_spoiler" class="flex1"></div> |
| 5487 | <i id="character_media_allowed_icon" class="fa-solid fa-fw fa-link"></i> | 5650 | <!-- A button to show / hide description_div and description_textarea and first_message_div and firstmessage_textarea--> |
| 5488 | <i id="character_media_forbidden_icon" class="fa-solid fa-fw fa-link-slash"></i> | ||
| 5489 | <span data-i18n="Ext. Media"> | ||
| 5490 | Ext. Media | ||
| 5491 | </span> | ||
| 5492 | </div> | ||
| 5493 | </div> | ||
| 5494 | <textarea id="description_textarea" class="mdHotkeys" data-i18n="[placeholder]Describe your character's physical and mental traits here." placeholder="Describe your character's physical and mental traits here." name="description" placeholder=""></textarea> | ||
| 5495 | <div class="extension_token_counter"> | ||
| 5496 | <span data-i18n="extension_token_counter">Tokens:</span> <span data-token-counter="description_textarea" data-token-permanent="true">counting...</span> | ||
| 5497 | </div> | 5651 | </div> |
| 5498 | </div> | 5652 | <div id="descriptionWrapper" class="flex-container flexFlowColumn flex1"> |
| 5499 | <div id="firstMessageWrapper" class="flex-container flexFlowColumn flex1"> | 5653 | <hr> |
| 5500 | <div id="first_message_div" class="title_restorable"> | 5654 | <div id="description_div" class="title_restorable"> |
| 5501 | <div class="flex-container alignitemscenter flex1"> | 5655 | <div class="flex-container alignitemscenter"> |
| 5502 | <span data-i18n="First message" class="mdhotkey_location">First message</span> | 5656 | <span data-i18n="Character Description" class="mdhotkey_location">Description</span> |
| 5503 | <i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="firstmessage_textarea" title="Expand the editor" data-i18n="[title]Expand the editor"></i> | 5657 | <i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="description_textarea" title="Expand the editor" data-i18n="[title]Expand the editor"></i> |
| 5504 | <a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#first-message" class="notes-link" target="_blank"> | 5658 | <a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#character-description" class="notes-link" target="_blank"> |
| 5505 | <span class="fa-solid fa-circle-question note-link-span"></span> | 5659 | <span class="fa-solid fa-circle-question note-link-span"></span> |
| 5506 | </a> | 5660 | </a> |
| 5661 | </div> | ||
| 5662 | <div id="character_open_media_overrides" class="menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this character." data-i18n="[title]Click to allow/forbid the use of external media for this character."> | ||
| 5663 | <i id="character_media_allowed_icon" class="fa-solid fa-fw fa-link"></i> | ||
| 5664 | <i id="character_media_forbidden_icon" class="fa-solid fa-fw fa-link-slash"></i> | ||
| 5665 | <span data-i18n="Ext. Media"> | ||
| 5666 | Ext. Media | ||
| 5667 | </span> | ||
| 5668 | </div> | ||
| 5507 | </div> | 5669 | </div> |
| 5508 | <div class="menu_button menu_button_icon open_alternate_greetings margin0" title="Click to set additional greeting messages" data-i18n="[title]Click to set additional greeting messages"> | 5670 | <textarea id="description_textarea" class="mdHotkeys" data-i18n="[placeholder]Describe your character's physical and mental traits here." placeholder="Describe your character's physical and mental traits here." name="description" placeholder=""></textarea> |
| 5509 | <span data-i18n="Alt. Greetings"> | 5671 | <div class="extension_token_counter"> |
| 5510 | Alt. Greetings | 5672 | <span data-i18n="extension_token_counter">Tokens:</span> <span data-token-counter="description_textarea" data-token-permanent="true">counting...</span> |
| 5511 | </span> | ||
| 5512 | </div> | 5673 | </div> |
| 5513 | </div> | 5674 | </div> |
| 5514 | <textarea class="mdHotkeys" id="firstmessage_textarea" data-i18n="[placeholder]This will be the first message from the character that starts every chat." placeholder="This will be the first message from the character that starts every chat." name="first_mes" placeholder=""></textarea> | 5675 | <div id="firstMessageWrapper" class="flex-container flexFlowColumn flex1"> |
| 5515 | <div class="extension_token_counter"> | 5676 | <div id="first_message_div" class="title_restorable"> |
| 5516 | <span data-i18n="extension_token_counter">Tokens:</span> <span data-token-counter="firstmessage_textarea">counting...</span> | 5677 | <div class="flex-container alignitemscenter flex1"> |
| 5517 | </div> | 5678 | <span data-i18n="First message" class="mdhotkey_location">First message</span> |
| 5518 | </div> | 5679 | <i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="firstmessage_textarea" title="Expand the editor" data-i18n="[title]Expand the editor"></i> |
| 5519 | <!-- these divs are invisible and used for server communication purposes --> | 5680 | <a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#first-message" class="notes-link" target="_blank"> |
| 5520 | <div id="hidden-divs"> | 5681 | <span class="fa-solid fa-circle-question note-link-span"></span> |
| 5521 | <input id="character_json_data" name="json_data" type="hidden"> | 5682 | </a> |
| 5522 | <input id="avatar_url_pole" name="avatar_url" type="hidden"> | 5683 | </div> |
| 5523 | <input id="selected_chat_pole" name="chat" type="hidden"> | 5684 | <div class="menu_button menu_button_icon open_alternate_greetings margin0" title="Click to set additional greeting messages" data-i18n="[title]Click to set additional greeting messages"> |
| 5524 | <input id="create_date_pole" name="create_date" type="hidden"> | 5685 | <span data-i18n="Alt. Greetings"> |
| 5525 | <input id="last_mes_pole" name="last_mes" type="hidden"> | 5686 | Alt. Greetings |
| 5526 | <input id="character_world" name="world" type="hidden"> | 5687 | </span> |
| 5527 | </div> | ||
| 5528 | <!-- now back to normal divs for display purposes--> | ||
| 5529 | </form> | ||
| 5530 | </div> | ||
| 5531 | <div name="Group Chat Edit Panel" id="rm_group_chats_block" class="right_menu flex-container flexNoGap"> | ||
| 5532 | <div class="inline-drawer wide100p flexFlowColumn"> | ||
| 5533 | <div id="groupControlsToggle" class="inline-drawer-toggle inline-drawer-header"> | ||
| 5534 | <span> | ||
| 5535 | <span data-i18n="Group Controls">Group Controls</span> | ||
| 5536 | <a href="https://docs.sillytavern.app/usage/core-concepts/groupchats/" class="notes-link" target="_blank"> | ||
| 5537 | <span class="fa-solid fa-circle-question note-link-span"></span> | ||
| 5538 | </a> | ||
| 5539 | </span> | ||
| 5540 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | ||
| 5541 | </div> | ||
| 5542 | <div class="inline-drawer-content"> | ||
| 5543 | <div id="group-metadata-controls" class="marginTopBot5"> | ||
| 5544 | <div class="flex-container wide100p"> | ||
| 5545 | <input id="rm_group_chat_name" class="text_pole flex1" type="text" name="chat_name" data-i18n="[placeholder]Chat Name (Optional)" placeholder="Chat Name (Optional)" /> | ||
| 5546 | <div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore" data-i18n="[title]Chat Lore"></div> | ||
| 5547 | </div> | ||
| 5548 | <div id="group_tags_div" class="wide100p"> | ||
| 5549 | <div class="tag_controls"> | ||
| 5550 | <input id="groupTagInput" class="text_pole textarea_compact tag_input flex1 margin0" data-i18n="[placeholder]Search / Create Tags" placeholder="Search / Create tags" /> | ||
| 5551 | <div class="tags_view menu_button fa-solid fa-tags margin0" title="View all tags" data-i18n="[title]View all tags"></div> | ||
| 5552 | </div> | 5688 | </div> |
| 5553 | <div id="groupTagList" class="tags paddingTopBot5"></div> | ||
| 5554 | </div> | 5689 | </div> |
| 5555 | <div id="rm_group_top_bar" class="flex-container alignitemscenter spaceBetween width100p fontsize80p"> | 5690 | <textarea class="mdHotkeys" id="firstmessage_textarea" data-i18n="[placeholder]This will be the first message from the character that starts every chat." placeholder="This will be the first message from the character that starts every chat." name="first_mes" placeholder=""></textarea> |
| 5556 | <div> | 5691 | <div class="extension_token_counter"> |
| 5557 | <label class="add_avatar avatar flex-container justifyCenter" for="group_avatar_button" title="Click to select a new avatar for this group" data-i18n="[title]Click to select a new avatar for this group"> | 5692 | <span data-i18n="extension_token_counter">Tokens:</span> <span data-token-counter="firstmessage_textarea">counting...</span> |
| 5558 | <div id="group_avatar_preview"> | 5693 | </div> |
| 5559 | <div class="avatar"> | 5694 | </div> |
| 5560 | <img src="img/ai4.png" alt="avatar"> | 5695 | <!-- these divs are invisible and used for server communication purposes --> |
| 5561 | </div> | 5696 | <div id="hidden-divs"> |
| 5562 | </div> | 5697 | <input id="character_json_data" name="json_data" type="hidden"> |
| 5563 | <input hidden type="file" id="group_avatar_button" name="avatar" accept="image/png, image/jpeg, image/jpg, image/gif, image/bmp"> | 5698 | <input id="avatar_url_pole" name="avatar_url" type="hidden"> |
| 5564 | </label> | 5699 | <input id="selected_chat_pole" name="chat" type="hidden"> |
| 5700 | <input id="create_date_pole" name="create_date" type="hidden"> | ||
| 5701 | <input id="last_mes_pole" name="last_mes" type="hidden"> | ||
| 5702 | <input id="character_world" name="world" type="hidden"> | ||
| 5703 | </div> | ||
| 5704 | <!-- now back to normal divs for display purposes--> | ||
| 5705 | </form> | ||
| 5706 | </div> | ||
| 5707 | <div name="Group Chat Edit Panel" id="rm_group_chats_block" class="right_menu flex-container flexNoGap"> | ||
| 5708 | <div class="inline-drawer wide100p flexFlowColumn"> | ||
| 5709 | <div id="groupControlsToggle" class="inline-drawer-toggle inline-drawer-header"> | ||
| 5710 | <span> | ||
| 5711 | <span data-i18n="Group Controls">Group Controls</span> | ||
| 5712 | <a href="https://docs.sillytavern.app/usage/core-concepts/groupchats/" class="notes-link" target="_blank"> | ||
| 5713 | <span class="fa-solid fa-circle-question note-link-span"></span> | ||
| 5714 | </a> | ||
| 5715 | </span> | ||
| 5716 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | ||
| 5717 | </div> | ||
| 5718 | <div class="inline-drawer-content"> | ||
| 5719 | <div id="group-metadata-controls" class="marginTopBot5"> | ||
| 5720 | <div class="flex-container wide100p"> | ||
| 5721 | <input id="rm_group_chat_name" class="text_pole flex1" type="text" name="chat_name" data-i18n="[placeholder]Chat Name (Optional)" placeholder="Chat Name (Optional)" /> | ||
| 5722 | <div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore" data-i18n="[title]Chat Lore"></div> | ||
| 5565 | </div> | 5723 | </div> |
| 5566 | <div name="GroupStragegyAndOrder" id="rm_group_buttons" class="flex-container paddingLeftRight5 flex2"> | 5724 | <div id="group_tags_div" class="wide100p"> |
| 5567 | <div class="flex1 flexGap5"> | 5725 | <div class="tag_controls"> |
| 5568 | <label for="rm_group_activation_strategy" class="flexnowrap width100p whitespacenowrap"> | 5726 | <input id="groupTagInput" class="text_pole textarea_compact tag_input flex1 margin0" data-i18n="[placeholder]Search / Create Tags" placeholder="Search / Create tags" /> |
| 5569 | <span data-i18n="Group reply strategy">Group reply strategy</span> | 5727 | <div class="tags_view menu_button fa-solid fa-tags margin0" title="View all tags" data-i18n="[title]View all tags"></div> |
| 5570 | </label> | ||
| 5571 | <select id="rm_group_activation_strategy"> | ||
| 5572 | <option value="2" data-i18n="Manual">Manual</option> | ||
| 5573 | <option value="0" data-i18n="Natural order">Natural order</option> | ||
| 5574 | <option value="1" data-i18n="List order">List order</option> | ||
| 5575 | <option value="3" data-i18n="Pooled order">Pooled order</option> | ||
| 5576 | </select> | ||
| 5577 | </div> | 5728 | </div> |
| 5578 | <div class="flex1 flexGap5"> | 5729 | <div id="groupTagList" class="tags paddingTopBot5"></div> |
| 5579 | <label for="rm_group_generation_mode" class="flexnowrap width100p whitespacenowrap"> | 5730 | </div> |
| 5580 | <span data-i18n="Group generation handling mode">Group generation handling mode</span> | 5731 | <div id="rm_group_top_bar" class="flex-container alignitemscenter spaceBetween width100p fontsize80p"> |
| 5581 | </label> | 5732 | <div> |
| 5582 | <select id="rm_group_generation_mode"> | 5733 | <label class="add_avatar avatar flex-container justifyCenter" for="group_avatar_button" title="Click to select a new avatar for this group" data-i18n="[title]Click to select a new avatar for this group"> |
| 5583 | <option value="0" data-i18n="Swap character cards">Swap character cards</option> | 5734 | <div id="group_avatar_preview"> |
| 5584 | <option value="1" data-i18n="Join character cards (exclude muted)">Join character cards (exclude muted)</option> | 5735 | <div class="avatar"> |
| 5585 | <option value="2" data-i18n="Join character cards (include muted)">Join character cards (include muted)</option> | 5736 | <img src="img/ai4.png" alt="avatar"> |
| 5586 | </select> | 5737 | </div> |
| 5587 | </div> | ||
| 5588 | <div class="flex1 flexGap5" title="Inserted before each part of the joined fields." data-i18n="[title]Inserted before each part of the joined fields."> | ||
| 5589 | <label for="rm_group_generation_mode_join_prefix" class="flexnowrap width100p whitespacenowrap"> | ||
| 5590 | <span data-i18n="Join Prefix">Join Prefix</span> | ||
| 5591 | <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)" title="When 'Join character cards' is selected, all respective fields of the characters are being joined together. This means that in the story string for example all character descriptions will be joined to one big text. If you want those fields to be separated, you can define a prefix or suffix here. This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)"> | ||
| 5592 | </div> | ||
| 5593 | </label> | ||
| 5594 | <textarea id="rm_group_generation_mode_join_prefix" class="text_pole wide100p textarea_compact autoSetHeight" placeholder="—" rows="1"></textarea> | ||
| 5595 | </div> | ||
| 5596 | <div class="flex1 flexGap5" title="Inserted after each part of the joined fields." data-i18n="[title]Inserted after each part of the joined fields."> | ||
| 5597 | <label for="rm_group_generation_mode_join_suffix" class="flexnowrap width100p whitespacenowrap"> | ||
| 5598 | <span data-i18n="Join Suffix">Join Suffix</span> | ||
| 5599 | <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)" title="When 'Join character cards' is selected, all respective fields of the characters are being joined together. This means that in the story string for example all character descriptions will be joined to one big text. If you want those fields to be separated, you can define a prefix or suffix here. This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)"> | ||
| 5600 | </div> | 5738 | </div> |
| 5739 | <input hidden type="file" id="group_avatar_button" name="avatar" accept="image/png, image/jpeg, image/jpg, image/gif, image/bmp"> | ||
| 5601 | </label> | 5740 | </label> |
| 5602 | <textarea id="rm_group_generation_mode_join_suffix" class="text_pole wide100p textarea_compact autoSetHeight" placeholder="—" rows="1"></textarea> | ||
| 5603 | </div> | 5741 | </div> |
| 5604 | </div> | 5742 | <div name="GroupStragegyAndOrder" id="rm_group_buttons" class="flex-container paddingLeftRight5 flex2"> |
| 5605 | <div id="GroupFavDelOkBack" class="flex-container flexGap5 spaceEvenly flex1"> | 5743 | <div class="flex1 flexGap5"> |
| 5606 | <div id="rm_button_back_from_group" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-left-long"></div> | 5744 | <label for="rm_group_activation_strategy" class="flexnowrap width100p whitespacenowrap"> |
| 5607 | <div id="rm_group_scenario" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-scroll" title="Set a group chat scenario" data-i18n="[title]Set a group chat scenario"></div> | 5745 | <span data-i18n="Group reply strategy">Group reply strategy</span> |
| 5608 | <div id="group_favorite_button" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div> | 5746 | </label> |
| 5609 | <input id="rm_group_fav" type="hidden" /> | 5747 | <select id="rm_group_activation_strategy"> |
| 5610 | <div id="group_open_media_overrides" class="heightFitContent margin0 menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this group." data-i18n="[title]Click to allow/forbid the use of external media for this group."> | 5748 | <option value="2" data-i18n="Manual">Manual</option> |
| 5611 | <i id="group_media_allowed_icon" class="fa-solid fa-fw fa-link"></i> | 5749 | <option value="0" data-i18n="Natural order">Natural order</option> |
| 5612 | <i id="group_media_forbidden_icon" class="fa-solid fa-fw fa-link-slash"></i> | 5750 | <option value="1" data-i18n="List order">List order</option> |
| 5751 | <option value="3" data-i18n="Pooled order">Pooled order</option> | ||
| 5752 | </select> | ||
| 5753 | </div> | ||
| 5754 | <div class="flex1 flexGap5"> | ||
| 5755 | <label for="rm_group_generation_mode" class="flexnowrap width100p whitespacenowrap"> | ||
| 5756 | <span data-i18n="Group generation handling mode">Group generation handling mode</span> | ||
| 5757 | </label> | ||
| 5758 | <select id="rm_group_generation_mode"> | ||
| 5759 | <option value="0" data-i18n="Swap character cards">Swap character cards</option> | ||
| 5760 | <option value="1" data-i18n="Join character cards (exclude muted)">Join character cards (exclude muted)</option> | ||
| 5761 | <option value="2" data-i18n="Join character cards (include muted)">Join character cards (include muted)</option> | ||
| 5762 | </select> | ||
| 5763 | </div> | ||
| 5764 | <div class="flex1 flexGap5" title="Inserted before each part of the joined fields." data-i18n="[title]Inserted before each part of the joined fields."> | ||
| 5765 | <label for="rm_group_generation_mode_join_prefix" class="flexnowrap width100p whitespacenowrap"> | ||
| 5766 | <span data-i18n="Join Prefix">Join Prefix</span> | ||
| 5767 | <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)" title="When 'Join character cards' is selected, all respective fields of the characters are being joined together. This means that in the story string for example all character descriptions will be joined to one big text. If you want those fields to be separated, you can define a prefix or suffix here. This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)"> | ||
| 5768 | </div> | ||
| 5769 | </label> | ||
| 5770 | <textarea id="rm_group_generation_mode_join_prefix" class="text_pole wide100p textarea_compact autoSetHeight" placeholder="—" rows="1"></textarea> | ||
| 5771 | </div> | ||
| 5772 | <div class="flex1 flexGap5" title="Inserted after each part of the joined fields." data-i18n="[title]Inserted after each part of the joined fields."> | ||
| 5773 | <label for="rm_group_generation_mode_join_suffix" class="flexnowrap width100p whitespacenowrap"> | ||
| 5774 | <span data-i18n="Join Suffix">Join Suffix</span> | ||
| 5775 | <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)" title="When 'Join character cards' is selected, all respective fields of the characters are being joined together. This means that in the story string for example all character descriptions will be joined to one big text. If you want those fields to be separated, you can define a prefix or suffix here. This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)"> | ||
| 5776 | </div> | ||
| 5777 | </label> | ||
| 5778 | <textarea id="rm_group_generation_mode_join_suffix" class="text_pole wide100p textarea_compact autoSetHeight" placeholder="—" rows="1"></textarea> | ||
| 5779 | </div> | ||
| 5613 | </div> | 5780 | </div> |
| 5614 | <div id="rm_group_submit" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-check" title="Create" data-i18n="[title]Create"></div> | 5781 | <div id="GroupFavDelOkBack" class="flex-container flexGap5 spaceEvenly flex1"> |
| 5615 | <div id="rm_group_restore_avatar" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-images" title="Restore collage avatar" data-i18n="[title]Restore collage avatar"></div> | 5782 | <div id="rm_button_back_from_group" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-left-long"></div> |
| 5616 | <div id="rm_group_delete" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-trash-can" title="Delete" data-i18n="[title]Delete"></div> | 5783 | <div id="rm_group_scenario" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-scroll" title="Set a group chat scenario" data-i18n="[title]Set a group chat scenario"></div> |
| 5617 | <div class="flex1"> | 5784 | <div id="group_favorite_button" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div> |
| 5618 | <label class="checkbox_label whitespacenowrap"> | 5785 | <input id="rm_group_fav" type="hidden" /> |
| 5619 | <input id="rm_group_allow_self_responses" type="checkbox" /> | 5786 | <div id="group_open_media_overrides" class="heightFitContent margin0 menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this group." data-i18n="[title]Click to allow/forbid the use of external media for this group."> |
| 5620 | <span data-i18n="Allow self responses">Allow self responses</span> | 5787 | <i id="group_media_allowed_icon" class="fa-solid fa-fw fa-link"></i> |
| 5621 | </label> | 5788 | <i id="group_media_forbidden_icon" class="fa-solid fa-fw fa-link-slash"></i> |
| 5622 | <label id="rm_group_automode_label" class="checkbox_label whitespacenowrap"> | 5789 | </div> |
| 5623 | <input id="rm_group_automode" type="checkbox" /> | 5790 | <div id="rm_group_submit" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-check" title="Create" data-i18n="[title]Create"></div> |
| 5624 | <span data-i18n="Auto Mode">Auto Mode</span> | 5791 | <div id="rm_group_restore_avatar" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-images" title="Restore collage avatar" data-i18n="[title]Restore collage avatar"></div> |
| 5625 | <input id="rm_group_automode_delay" class="text_pole textarea_compact widthUnset" type="number" min="1" max="999" step="1" value="5" title="Auto Mode delay" data-i18n="[title]Auto Mode delay" /> | 5792 | <div id="rm_group_delete" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-trash-can" title="Delete" data-i18n="[title]Delete"></div> |
| 5626 | </label> | 5793 | <div class="flex1"> |
| 5627 | <label id="rm_group_hidemutedsprites_label" class="checkbox_label whitespacenowrap"> | 5794 | <label class="checkbox_label whitespacenowrap"> |
| 5628 | <input id="rm_group_hidemutedsprites" type="checkbox" /> | 5795 | <input id="rm_group_allow_self_responses" type="checkbox" /> |
| 5629 | <span data-i18n="Hide Muted Member Sprites">Hide Muted Member Sprites</span> | 5796 | <span data-i18n="Allow self responses">Allow self responses</span> |
| 5630 | </label> | 5797 | </label> |
| 5798 | <label id="rm_group_automode_label" class="checkbox_label whitespacenowrap"> | ||
| 5799 | <input id="rm_group_automode" type="checkbox" /> | ||
| 5800 | <span data-i18n="Auto Mode">Auto Mode</span> | ||
| 5801 | <input id="rm_group_automode_delay" class="text_pole textarea_compact widthUnset" type="number" min="1" max="999" step="1" value="5" title="Auto Mode delay" data-i18n="[title]Auto Mode delay" /> | ||
| 5802 | </label> | ||
| 5803 | <label id="rm_group_hidemutedsprites_label" class="checkbox_label whitespacenowrap"> | ||
| 5804 | <input id="rm_group_hidemutedsprites" type="checkbox" /> | ||
| 5805 | <span data-i18n="Hide Muted Member Sprites">Hide Muted Member Sprites</span> | ||
| 5806 | </label> | ||
| 5807 | </div> | ||
| 5631 | </div> | 5808 | </div> |
| 5632 | </div> | 5809 | </div> |
| 5633 | </div> | 5810 | </div> |
| 5634 | </div> | 5811 | </div> |
| 5635 | </div> | 5812 | </div> |
| 5636 | </div> | 5813 | <div class="inline-drawer wide100p flexFlowColumn"> |
| 5637 | <div class="inline-drawer wide100p flexFlowColumn"> | 5814 | <div id="groupCurrentMemberListToggle" class="inline-drawer-toggle inline-drawer-header"> |
| 5638 | <div id="groupCurrentMemberListToggle" class="inline-drawer-toggle inline-drawer-header"> | 5815 | <span data-i18n="Current Members">Current Members </span><i id="groupCurrentMemberPopoutButton" class="fa-solid fa-window-restore menu_button"></i> |
| 5639 | <span data-i18n="Current Members">Current Members </span><i id="groupCurrentMemberPopoutButton" class="fa-solid fa-window-restore menu_button"></i> | 5816 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> |
| 5640 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | ||
| 5641 | </div> | ||
| 5642 | <div class="inline-drawer-content"> | ||
| 5643 | <div id="currentGroupMembers" name="Current Group Members" class="flex-container flexFlowColumn overflowYAuto flex1"> | ||
| 5644 | <div id="rm_group_members_pagination" class="rm_group_members_pagination group_pagination"></div> | ||
| 5645 | <div id="rm_group_members" class="rm_group_members overflowYAuto flex-container" group_empty_text="Group is empty." data-i18n="[group_empty_text]Group is empty."></div> | ||
| 5646 | </div> | 5817 | </div> |
| 5647 | </div> | 5818 | <div class="inline-drawer-content"> |
| 5648 | </div> | 5819 | <div id="currentGroupMembers" name="Current Group Members" class="flex-container flexFlowColumn overflowYAuto flex1"> |
| 5649 | <div class="inline-drawer wide100p flexFlowColumn"> | 5820 | <div id="rm_group_members_pagination" class="rm_group_members_pagination group_pagination"></div> |
| 5650 | <div id="groupAddMemberListToggle" class="inline-drawer-toggle inline-drawer-header"> | 5821 | <div id="rm_group_members" class="rm_group_members overflowYAuto flex-container" group_empty_text="Group is empty." data-i18n="[group_empty_text]Group is empty."></div> |
| 5651 | <span data-i18n="Add Members">Add Members</span> | ||
| 5652 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | ||
| 5653 | </div> | ||
| 5654 | <div class="inline-drawer-content"> | ||
| 5655 | <div name="Unadded Char List" class="flex-container flexFlowColumn overflowYAuto flex1"> | ||
| 5656 | <div id="rm_group_add_members_header"> | ||
| 5657 | <input id="rm_group_filter" class="text_pole margin0" type="search" data-i18n="[placeholder]Search..." placeholder="Search..." /> | ||
| 5658 | </div> | 5822 | </div> |
| 5659 | <div class="rm_tag_controls"> | 5823 | </div> |
| 5660 | <div class="tags rm_tag_filter"></div> | 5824 | </div> |
| 5825 | <div class="inline-drawer wide100p flexFlowColumn"> | ||
| 5826 | <div id="groupAddMemberListToggle" class="inline-drawer-toggle inline-drawer-header"> | ||
| 5827 | <span data-i18n="Add Members">Add Members</span> | ||
| 5828 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | ||
| 5829 | </div> | ||
| 5830 | <div class="inline-drawer-content"> | ||
| 5831 | <div name="Unadded Char List" class="flex-container flexFlowColumn overflowYAuto flex1"> | ||
| 5832 | <div id="rm_group_add_members_header"> | ||
| 5833 | <input id="rm_group_filter" class="text_pole margin0" type="search" data-i18n="[placeholder]Search..." placeholder="Search..." /> | ||
| 5834 | </div> | ||
| 5835 | <div class="rm_tag_controls"> | ||
| 5836 | <div class="tags rm_tag_filter"></div> | ||
| 5837 | </div> | ||
| 5838 | <div id="rm_group_add_members_pagination" class="group_pagination"></div> | ||
| 5839 | <div id="rm_group_add_members" class="overflowYAuto flex-container" no_characters_text="No characters available" data-i18n="[no_characters_text]No characters available"></div> | ||
| 5661 | </div> | 5840 | </div> |
| 5662 | <div id="rm_group_add_members_pagination" class="group_pagination"></div> | ||
| 5663 | <div id="rm_group_add_members" class="overflowYAuto flex-container" no_characters_text="No characters available" data-i18n="[no_characters_text]No characters available"></div> | ||
| 5664 | </div> | 5841 | </div> |
| 5665 | </div> | 5842 | </div> |
| 5666 | </div> | 5843 | </div> |
| 5667 | </div> | 5844 | <div id="rm_character_import" class="right_menu" style="display: none;"> |
| 5668 | <div id="rm_character_import" class="right_menu" style="display: none;"> | 5845 | <form id="form_import" action="javascript:void(null);" method="post" enctype="multipart/form-data"> |
| 5669 | <form id="form_import" action="javascript:void(null);" method="post" enctype="multipart/form-data"> | 5846 | <input multiple type="file" id="character_import_file" accept=".json, image/png, .yaml, .yml, .charx" name="avatar"> |
| 5670 | <input multiple type="file" id="character_import_file" accept=".json, image/png, .yaml, .yml, .charx" name="avatar"> | 5847 | <input id="character_import_file_type" name="file_type" class="text_pole" value="" autocomplete="off"> |
| 5671 | <input id="character_import_file_type" name="file_type" class="text_pole" value="" autocomplete="off"> | ||
| 5672 | </form> | ||
| 5673 | <input type="file" id="character_replace_file" accept=".json, image/png, .yaml, .yml, .charx" name="replace_avatar" hidden> | ||
| 5674 | </div> | ||
| 5675 | <div name="Character List Panel" id="rm_characters_block" class="right_menu"> | ||
| 5676 | <div id="charListFixedTop"> | ||
| 5677 | <form id="form_character_search_form" action="javascript:void(null);"> | ||
| 5678 | <div id="rm_button_create" title="Create New Character" data-i18n="[title]Create New Character" class="menu_button fa-solid fa-user-plus "></div> | ||
| 5679 | <div id="character_import_button" title="Import Character from File" data-i18n="[title]Import Character from File" class="menu_button fa-solid fa-file-import faSmallFontSquareFix"></div> | ||
| 5680 | <div id="external_import_button" title="Import content from external URL" data-i18n="[title]Import content from external URL" class="menu_button fa-solid fa-cloud-arrow-down faSmallFontSquareFix"></div> | ||
| 5681 | <div id="rm_button_group_chats" title="Create New Chat Group" data-i18n="[title]Create New Chat Group" class="menu_button fa-solid fa-users-gear "></div> | ||
| 5682 | <input id="character_search_bar" class="text_pole width100p" type="search" data-i18n="[placeholder]Search..." placeholder="Search..." /> | ||
| 5683 | <select id="character_sort_order" title="Characters sorting order" data-i18n="[title]Characters sorting order"> | ||
| 5684 | <option data-field="search" data-order="desc" data-i18n="Search" hidden>Search</option> | ||
| 5685 | <option data-field="name" data-order="asc" data-i18n="A-Z">A-Z</option> | ||
| 5686 | <option data-field="name" data-order="desc" data-i18n="Z-A">Z-A</option> | ||
| 5687 | <option data-field="create_date" data-order="desc" data-i18n="Newest">Newest</option> | ||
| 5688 | <option data-field="create_date" data-order="asc" data-i18n="Oldest">Oldest</option> | ||
| 5689 | <option data-field="fav" data-order="desc" data-rule="boolean" data-i18n="Favorites">Favorites</option> | ||
| 5690 | <option data-field="date_last_chat" data-order="desc" data-i18n="Recent">Recent</option> | ||
| 5691 | <option data-field="chat_size" data-order="desc" data-i18n="Most chats">Most chats</option> | ||
| 5692 | <option data-field="chat_size" data-order="asc" data-i18n="Least chats">Least chats</option> | ||
| 5693 | <option data-field="data_size" data-order="desc" data-i18n="Most tokens">Most tokens</option> | ||
| 5694 | <option data-field="data_size" data-order="asc" data-i18n="Least tokens">Least tokens</option> | ||
| 5695 | <option data-field="name" data-order="random" data-i18n="Random">Random</option> | ||
| 5696 | </select> | ||
| 5697 | </form> | 5848 | </form> |
| 5698 | <div class="rm_tag_controls"> | 5849 | <input type="file" id="character_replace_file" accept=".json, image/png, .yaml, .yml, .charx" name="replace_avatar" hidden> |
| 5699 | <div class="tags rm_tag_filter"></div> | ||
| 5700 | <div class="tags rm_tag_bogus_drilldown"></div> | ||
| 5701 | </div> | ||
| 5702 | <hr> | ||
| 5703 | </div> | 5850 | </div> |
| 5851 | <div name="Character List Panel" id="rm_characters_block" class="right_menu"> | ||
| 5852 | <div id="charListFixedTop"> | ||
| 5853 | <form id="form_character_search_form" action="javascript:void(null);"> | ||
| 5854 | <div id="rm_button_create" title="Create New Character" data-i18n="[title]Create New Character" class="menu_button fa-solid fa-user-plus "></div> | ||
| 5855 | <div id="character_import_button" title="Import Character from File" data-i18n="[title]Import Character from File" class="menu_button fa-solid fa-file-import faSmallFontSquareFix"></div> | ||
| 5856 | <div id="external_import_button" title="Import content from external URL" data-i18n="[title]Import content from external URL" class="menu_button fa-solid fa-cloud-arrow-down faSmallFontSquareFix"></div> | ||
| 5857 | <div id="rm_button_group_chats" title="Create New Chat Group" data-i18n="[title]Create New Chat Group" class="menu_button fa-solid fa-users-gear "></div> | ||
| 5858 | <input id="character_search_bar" class="text_pole width100p" type="search" data-i18n="[placeholder]Search..." placeholder="Search..." /> | ||
| 5859 | <select id="character_sort_order" title="Characters sorting order" data-i18n="[title]Characters sorting order"> | ||
| 5860 | <option data-field="search" data-order="desc" data-i18n="Search" hidden>Search</option> | ||
| 5861 | <option data-field="name" data-order="asc" data-i18n="A-Z">A-Z</option> | ||
| 5862 | <option data-field="name" data-order="desc" data-i18n="Z-A">Z-A</option> | ||
| 5863 | <option data-field="create_date" data-order="desc" data-i18n="Newest">Newest</option> | ||
| 5864 | <option data-field="create_date" data-order="asc" data-i18n="Oldest">Oldest</option> | ||
| 5865 | <option data-field="fav" data-order="desc" data-rule="boolean" data-i18n="Favorites">Favorites</option> | ||
| 5866 | <option data-field="date_last_chat" data-order="desc" data-i18n="Recent">Recent</option> | ||
| 5867 | <option data-field="chat_size" data-order="desc" data-i18n="Most chats">Most chats</option> | ||
| 5868 | <option data-field="chat_size" data-order="asc" data-i18n="Least chats">Least chats</option> | ||
| 5869 | <option data-field="data_size" data-order="desc" data-i18n="Most tokens">Most tokens</option> | ||
| 5870 | <option data-field="data_size" data-order="asc" data-i18n="Least tokens">Least tokens</option> | ||
| 5871 | <option data-field="name" data-order="random" data-i18n="Random">Random</option> | ||
| 5872 | </select> | ||
| 5873 | </form> | ||
| 5874 | <div class="rm_tag_controls"> | ||
| 5875 | <div class="tags rm_tag_filter"></div> | ||
| 5876 | <div class="tags rm_tag_bogus_drilldown"></div> | ||
| 5877 | </div> | ||
| 5878 | <hr> | ||
| 5879 | </div> | ||
| 5704 | 5880 | ||
| 5705 | <div id="rm_print_characters_pagination"> | 5881 | <div id="rm_print_characters_pagination"> |
| 5706 | <i id="charListGridToggle" class="fa-solid fa-table-cells-large menu_button" title="Toggle character grid view" data-i18n="[title]Toggle character grid view"></i> | 5882 | <i id="charListGridToggle" class="fa-solid fa-table-cells-large menu_button" title="Toggle character grid view" data-i18n="[title]Toggle character grid view"></i> |
| 5707 | <i id="bulkEditButton" class="fa-solid fa-edit menu_button bulkEditButton" title="Bulk edit characters Click to toggle characters Shift + Click to select/deselect a range of characters Right-click for actions" data-i18n="[title]Bulk_edit_characters"></i> | 5883 | <i id="bulkEditButton" class="fa-solid fa-edit menu_button bulkEditButton" title="Bulk edit characters Click to toggle characters Shift + Click to select/deselect a range of characters Right-click for actions" data-i18n="[title]Bulk_edit_characters"></i> |
| 5708 | <div id="bulkSelectedCount" class="bulkEditOptionElement paginationjs-nav"></div> | 5884 | <div id="bulkSelectedCount" class="bulkEditOptionElement paginationjs-nav"></div> |
| 5709 | <i id="bulkSelectAllButton" class="fa-solid fa-check-double menu_button bulkEditOptionElement bulkSelectAllButton" title="Bulk select all characters" data-i18n="[title]Bulk select all characters" style="display: none;"></i> | 5885 | <i id="bulkSelectAllButton" class="fa-solid fa-check-double menu_button bulkEditOptionElement bulkSelectAllButton" title="Bulk select all characters" data-i18n="[title]Bulk select all characters" style="display: none;"></i> |
| 5710 | <i id="bulkDeleteButton" class="fa-solid fa-trash menu_button bulkEditOptionElement bulkDeleteButton" title="Bulk delete characters" data-i18n="[title]Bulk delete characters" style="display: none;"></i> | 5886 | <i id="bulkDeleteButton" class="fa-solid fa-trash menu_button bulkEditOptionElement bulkDeleteButton" title="Bulk delete characters" data-i18n="[title]Bulk delete characters" style="display: none;"></i> |
| 5887 | </div> | ||
| 5888 | <div id="rm_print_characters_block" class="flexFlowColumn"></div> | ||
| 5711 | </div> | 5889 | </div> |
| 5712 | <div id="rm_print_characters_block" class="flexFlowColumn"></div> | ||
| 5713 | </div> | 5890 | </div> |
| 5714 | </nav> | 5891 | </nav> |
| 5715 | </div> | 5892 | </div> |
| @@ -6086,6 +6263,298 @@ | |||
| 6086 | </div> | 6263 | </div> |
| 6087 | </div> | 6264 | </div> |
| 6088 | <div id="entry_edit_template" class="template_element"> | 6265 | <div id="entry_edit_template" class="template_element"> |
| 6266 | <div class="world_entry_edit"> | ||
| 6267 | <div class="flex-container wide100p alignitemscenter"> | ||
| 6268 | <div name="keywordsAndLogicBlock" class="flex-container wide100p alignitemscenter"> | ||
| 6269 | <div class="world_entry_form_control keyprimary flex1"> | ||
| 6270 | <small class="displayNone"> | ||
| 6271 | <span data-i18n="Comma separated (required)"> | ||
| 6272 | Comma separated (required) | ||
| 6273 | </span> | ||
| 6274 | </small> | ||
| 6275 | <small class="textAlignCenter" data-i18n="Primary Keywords">Primary Keywords</small> | ||
| 6276 | <select class="keyprimaryselect keyselect select2_multi_sameline" name="key" data-i18n="[placeholder]Keywords or Regexes" placeholder="Keywords or Regexes" multiple="multiple"></select> | ||
| 6277 | <textarea class="text_pole keyprimarytextpole mobile" name="key" rows="1" data-i18n="[placeholder]Comma separated list" placeholder="Comma separated list" style="display: none;"></textarea> | ||
| 6278 | <button type="button" class="switch_input_type_icon" tabindex="-1" title="Switch to plaintext mode" data-i18n="[title]Switch to plaintext mode" data-icon-on="✨" data-icon-off="⌨️" data-tooltip-on="Switch to fancy mode" data-tooltip-off="Switch to plaintext mode"> | ||
| 6279 | ⌨️ | ||
| 6280 | </button> | ||
| 6281 | </div> | ||
| 6282 | <div class="world_entry_form_control"> | ||
| 6283 | <small class="textAlignCenter" data-i18n="Logic">Logic</small> | ||
| 6284 | <select name="entryLogicType" class="text_pole widthFitContent margin0"> | ||
| 6285 | <option value="0" data-i18n="AND ANY">AND ANY</option> | ||
| 6286 | <option value="3" data-i18n="AND ALL">AND ALL</option> | ||
| 6287 | <option value="1" data-i18n="NOT ALL">NOT ALL</option> | ||
| 6288 | <option value="2" data-i18n="NOT ANY">NOT ANY</option> | ||
| 6289 | </select> | ||
| 6290 | </div> | ||
| 6291 | <div class="world_entry_form_control keysecondary flex1"> | ||
| 6292 | <small class="displayNone"> | ||
| 6293 | <span data-i18n="(ignored if empty)"> | ||
| 6294 | (ignored if empty) | ||
| 6295 | </span> | ||
| 6296 | </small> | ||
| 6297 | <small class="textAlignCenter" data-i18n="Optional Filter">Optional Filter</small> | ||
| 6298 | <select class="keysecondaryselect keyselect select2_multi_sameline" name="keysecondary" data-i18n="[placeholder]Keywords or Regexes (ignored if empty)" placeholder="Keywords or Regexes (ignored if empty)" multiple="multiple"></select> | ||
| 6299 | <textarea class="text_pole keysecondarytextpole mobile" name="keysecondary" rows="1" data-i18n="[placeholder]Comma separated list (ignored if empty)" placeholder="Comma separated list (ignored if empty)" style="display: none;"></textarea> | ||
| 6300 | <button type="button" class="switch_input_type_icon" tabindex="-1" title="Switch to plaintext mode" data-i18n="[title]Switch to plaintext mode" data-icon-on="✨" data-icon-off="⌨️" data-tooltip-on="Switch to fancy mode" data-tooltip-off="Switch to plaintext mode"> | ||
| 6301 | ⌨️ | ||
| 6302 | </button> | ||
| 6303 | </div> | ||
| 6304 | </div> | ||
| 6305 | <div name="perEntryOverridesBlock" class="flex-container wide100p alignitemscenter"> | ||
| 6306 | <div class="world_entry_form_control flex1"> | ||
| 6307 | <small class="textAlignCenter" data-i18n="Scan Depth">Scan Depth</small> | ||
| 6308 | <input class="text_pole margin0" name="scanDepth" type="number" placeholder="Use global setting" data-i18n="[placeholder]Use global setting" max="1000"> | ||
| 6309 | </div> | ||
| 6310 | <div class="world_entry_form_control flex1"> | ||
| 6311 | <small class="textAlignCenter" data-i18n="Case-Sensitive">Case-Sensitive</small> | ||
| 6312 | <select name="caseSensitive" class="text_pole widthNatural margin0"> | ||
| 6313 | <option value="null" data-i18n="Use global">Use global</option> | ||
| 6314 | <option value="true" data-i18n="Yes">Yes</option> | ||
| 6315 | <option value="false" data-i18n="No">No</option> | ||
| 6316 | </select> | ||
| 6317 | </div> | ||
| 6318 | <div class="world_entry_form_control flex1"> | ||
| 6319 | <small class="textAlignCenter" data-i18n="Whole Words">Whole Words</small> | ||
| 6320 | <select name="matchWholeWords" class="text_pole widthNatural margin0"> | ||
| 6321 | <option value="null" data-i18n="Use global">Use global</option> | ||
| 6322 | <option value="true" data-i18n="Yes">Yes</option> | ||
| 6323 | <option value="false" data-i18n="No">No</option> | ||
| 6324 | </select> | ||
| 6325 | </div> | ||
| 6326 | <div class="world_entry_form_control flex1"> | ||
| 6327 | <small class="textAlignCenter" data-i18n="Group Scoring">Group Scoring</small> | ||
| 6328 | <select name="useGroupScoring" class="text_pole widthNatural margin0"> | ||
| 6329 | <option value="null" data-i18n="Use global">Use global</option> | ||
| 6330 | <option value="true" data-i18n="Yes">Yes</option> | ||
| 6331 | <option value="false" data-i18n="No">No</option> | ||
| 6332 | </select> | ||
| 6333 | </div> | ||
| 6334 | <div class="world_entry_form_control flex1" title="Can be used to automatically activate Quick Replies" data-i18n="[title]Can be used to automatically activate Quick Replies"> | ||
| 6335 | <small class="textAlignCenter" data-i18n="Automation ID">Automation ID</small> | ||
| 6336 | <input class="text_pole margin0" name="automationId" type="text" placeholder="( None )" data-i18n="[placeholder]( None )"> | ||
| 6337 | </div> | ||
| 6338 | <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"> | ||
| 6339 | <small class="textAlignCenter"> | ||
| 6340 | <span data-i18n="Recursion Level">Recursion Level</span> | ||
| 6341 | <div class="fa-solid fa-circle-info opacity50p"></div> | ||
| 6342 | </small> | ||
| 6343 | <input class="text_pole margin0" name="delayUntilRecursionLevel" type="text" placeholder="1"> | ||
| 6344 | </div> | ||
| 6345 | </div> | ||
| 6346 | <div name="contentAndCharFilterBlock" class="world_entry_thin_controls flex2"> | ||
| 6347 | <div class="world_entry_form_control flex1"> | ||
| 6348 | <label for="content "> | ||
| 6349 | <small> | ||
| 6350 | <span class="alignitemscenter flex-container flexnowrap wide100p justifySpaceBetween"> | ||
| 6351 | <span class="alignitemscenter flex-container"> | ||
| 6352 | <span data-i18n="Content" class="mdhotkey_location"> | ||
| 6353 | Content | ||
| 6354 | </span> | ||
| 6355 | <i class="editor_maximize fa-solid fa-maximize right_menu_button" title="Expand the editor" data-i18n="[title]Expand the editor"></i> | ||
| 6356 | </span> | ||
| 6357 | <span> | ||
| 6358 | (<span data-i18n="extension_token_counter">Tokens:</span> <span class="world_entry_form_token_counter" data-first-run="true">counting...</span>) | ||
| 6359 | <span class="world_entry_form_uid_value" data-first-run="true"></span> | ||
| 6360 | </span> | ||
| 6361 | <div> | ||
| 6362 | <label class="checkbox flex-container alignitemscenter flexNoGap"> | ||
| 6363 | <input type="checkbox" name="excludeRecursion" /> | ||
| 6364 | <span data-i18n="Non-recursable (will not be activated by another)"> | ||
| 6365 | Non-recursable (will not be activated by another) | ||
| 6366 | </span> | ||
| 6367 | </label> | ||
| 6368 | <label class="checkbox flex-container alignitemscenter flexNoGap"> | ||
| 6369 | <input type="checkbox" name="preventRecursion" /> | ||
| 6370 | <span data-i18n="Prevent further recursion (this entry will not activate others)"> | ||
| 6371 | Prevent further recursion (will not activate others) | ||
| 6372 | </span> | ||
| 6373 | </label> | ||
| 6374 | <label class="checkbox flex-container alignitemscenter flexNoGap"> | ||
| 6375 | <input type="checkbox" name="delay_until_recursion" /> | ||
| 6376 | <span data-i18n="Delay until recursion (can only be activated on recursive checking)"> | ||
| 6377 | Delay until recursion (can only be activated on recursive checking) | ||
| 6378 | </span> | ||
| 6379 | </label> | ||
| 6380 | </div> | ||
| 6381 | </span> | ||
| 6382 | </small> | ||
| 6383 | <small class="displayNone"> | ||
| 6384 | <span data-i18n="What this keyword should mean to the AI, sent verbatim"> | ||
| 6385 | What this keyword should mean to the AI, sent verbatim | ||
| 6386 | </span> | ||
| 6387 | </small> | ||
| 6388 | </label> | ||
| 6389 | <textarea class="text_pole mdHotkeys" name="content" rows="8" data-i18n="[placeholder]What this keyword should mean to the AI, sent verbatim" placeholder="What this keyword should mean to the AI, sent verbatim"></textarea> | ||
| 6390 | </div> | ||
| 6391 | </div> | ||
| 6392 | <div class="world_entry_thin_controls commentContainer"> | ||
| 6393 | </div> | ||
| 6394 | </div> | ||
| 6395 | <div class="flex-container wide100p flexGap10"> | ||
| 6396 | <div class="flex4 flex-container flexFlowColumn flexNoGap"> | ||
| 6397 | <div class="flex-container justifySpaceBetween"> | ||
| 6398 | <small for="group"> | ||
| 6399 | <span data-i18n="Inclusion Group">Inclusion Group</span> | ||
| 6400 | <a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/#inclusion-group" class="notes-link" target="_blank" title="Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered. Supports multiple comma-separated groups. Documentation: World Info - Inclusion Group" data-i18n="[title]Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group"> | ||
| 6401 | <span class="fa-solid fa-circle-question note-link-span"></span> | ||
| 6402 | </a> | ||
| 6403 | </small> | ||
| 6404 | <label class="checkbox_label flexNoGap margin-r5" for="groupOverride"> | ||
| 6405 | <input type="checkbox" name="groupOverride" /> | ||
| 6406 | <span> | ||
| 6407 | <small title="Prioritize this entry: When checked, this entry is prioritized out of all selections. If multiple are prioritized, the one with the highest 'Order' is chosen. " data-i18n="[title]Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen."> | ||
| 6408 | <span data-i18n="Prioritize">Prioritize</span> | ||
| 6409 | <div class="fa-solid fa-circle-info opacity50p"></div> | ||
| 6410 | </small> | ||
| 6411 | </span> | ||
| 6412 | </label> | ||
| 6413 | </div> | ||
| 6414 | <div class="range-block-range"> | ||
| 6415 | <input type="text" class="text_pole margin0" name="group" rows="1" data-i18n="[placeholder]Only one entry with the same label will be activated" placeholder="Only one entry with the same label will be activated"> | ||
| 6416 | </div> | ||
| 6417 | </div> | ||
| 6418 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]A relative likelihood of entry activation within the group" title="A relative likelihood of entry activation within the group"> | ||
| 6419 | <div class="flex-container justifySpaceBetween marginBot5"> | ||
| 6420 | <small for="groupWeight" data-i18n="Group Weight"> | ||
| 6421 | Group Weight | ||
| 6422 | </small> | ||
| 6423 | </div> | ||
| 6424 | <div class="range-block-range"> | ||
| 6425 | <input type="number" class="text_pole margin0" name="groupWeight" rows="1" placeholder="100" min="1" max="999999"> | ||
| 6426 | </div> | ||
| 6427 | </div> | ||
| 6428 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Sticky entries will stay active for N messages after being triggered." title="Sticky entries will stay active for N messages after being triggered."> | ||
| 6429 | <div class="flex-container justifySpaceBetween marginBot5"> | ||
| 6430 | <small class="flex-container alignItemsBaseline" for="sticky"> | ||
| 6431 | <span data-i18n="Sticky"> | ||
| 6432 | Sticky | ||
| 6433 | </span> | ||
| 6434 | <i class="fa-solid fa-comments fa-xs"></i> | ||
| 6435 | </small> | ||
| 6436 | </div> | ||
| 6437 | <div class="range-block-range"> | ||
| 6438 | <input class="text_pole margin0" name="sticky" type="number" data-i18n="[placeholder]Non-sticky" placeholder="Non-sticky" min="0" max="999999"> | ||
| 6439 | </div> | ||
| 6440 | </div> | ||
| 6441 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a cooldown can't be activated N messages after being triggered." title="Entries with a cooldown can't be activated N messages after being triggered."> | ||
| 6442 | <div class="flex-container justifySpaceBetween marginBot5"> | ||
| 6443 | <small class="flex-container alignItemsBaseline" for="cooldown"> | ||
| 6444 | <span data-i18n="Cooldown"> | ||
| 6445 | Cooldown | ||
| 6446 | </span> | ||
| 6447 | <i class="fa-solid fa-comments fa-xs"></i> | ||
| 6448 | </small> | ||
| 6449 | </div> | ||
| 6450 | <div class="range-block-range"> | ||
| 6451 | <input class="text_pole margin0" name="cooldown" type="number" data-i18n="[placeholder]No cooldown" placeholder="No cooldown" min="0" max="999999"> | ||
| 6452 | </div> | ||
| 6453 | </div> | ||
| 6454 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a delay can't be activated until there are N messages present in the chat." title="Entries with a delay can't be activated until there are N messages present in the chat."> | ||
| 6455 | <div class="flex-container justifySpaceBetween marginBot5"> | ||
| 6456 | <small class="flex-container alignItemsBaseline" for="delay"> | ||
| 6457 | <span data-i18n="Delay"> | ||
| 6458 | Delay | ||
| 6459 | </span> | ||
| 6460 | <i class="fa-solid fa-comments fa-xs"></i> | ||
| 6461 | </small> | ||
| 6462 | </div> | ||
| 6463 | <div class="range-block-range"> | ||
| 6464 | <input class="text_pole margin0" name="delay" type="number" data-i18n="[placeholder]No delay" placeholder="No delay" min="0" max="999999"> | ||
| 6465 | </div> | ||
| 6466 | </div> | ||
| 6467 | </div> | ||
| 6468 | <div class="flex-container wide100p flexGap10"> | ||
| 6469 | <div class="flex4 flex-container flexFlowColumn flexNoGap"> | ||
| 6470 | <div class="flex-container justifySpaceBetween"> | ||
| 6471 | <small for="characterFilter" data-i18n="Filter to Characters or Tags"> | ||
| 6472 | Filter to Characters or Tags | ||
| 6473 | </small> | ||
| 6474 | <label class="checkbox_label flexNoGap margin-r5" for="character_exclusion"> | ||
| 6475 | <input type="checkbox" name="character_exclusion" /> | ||
| 6476 | <span> | ||
| 6477 | <small title="Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry" data-i18n="[title]Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry"> | ||
| 6478 | <span data-i18n="Exclude">Exclude</span> | ||
| 6479 | <div class="fa-solid fa-circle-info opacity50p"></div> | ||
| 6480 | </small> | ||
| 6481 | </span> | ||
| 6482 | </label> | ||
| 6483 | </div> | ||
| 6484 | <div class="range-block-range"> | ||
| 6485 | <select name="characterFilter" class="select2_multi_sameline" multiple> | ||
| 6486 | <option value="" data-i18n="-- Characters not found --"> | ||
| 6487 | -- Characters not found -- | ||
| 6488 | </option> | ||
| 6489 | </select> | ||
| 6490 | </div> | ||
| 6491 | </div> | ||
| 6492 | </div> | ||
| 6493 | <div name="WIEntryBottomControls" class="flex-container flex1 justifySpaceBetween world_entry_form_horizontal"> | ||
| 6494 | <div class="flex-container flexFlowColumn flexNoGap wi-enter-footer-text"> | ||
| 6495 | <label class="checkbox flex-container"> | ||
| 6496 | <input type="checkbox" name="selective" /> | ||
| 6497 | <span data-i18n="Selective">Selective</span> | ||
| 6498 | </label> | ||
| 6499 | <label class="checkbox flex-container"> | ||
| 6500 | <input type="checkbox" name="useProbability" /> | ||
| 6501 | <span data-i18n="Use Probability">Use Probability</span> | ||
| 6502 | </label> | ||
| 6503 | <label class="checkbox flex-container"> | ||
| 6504 | <input type="checkbox" name="addMemo"> | ||
| 6505 | <span data-i18n="Add Memo">Add Memo</span> | ||
| 6506 | </label> | ||
| 6507 | </div> | ||
| 6508 | </div> | ||
| 6509 | <div class="inline-drawer wide100p flexFlowColumn"> | ||
| 6510 | <div class="inline-drawer-toggle inline-drawer-header inline-drawer-header-pointer userSettingsInnerExpandable"> | ||
| 6511 | <strong data-i18n="Additional Matching Sources">Additional Matching Sources</strong> | ||
| 6512 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | ||
| 6513 | </div> | ||
| 6514 | <div class="inline-drawer-content flex-container flexFlowRow flexGap10 paddingBottom5px"> | ||
| 6515 | <small class="flex-container flex1 flexFlowColumn"> | ||
| 6516 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6517 | <input type="checkbox" name="matchCharacterDescription" /> | ||
| 6518 | <span data-i18n="Character Description"> | ||
| 6519 | Character Description | ||
| 6520 | </span> | ||
| 6521 | </label> | ||
| 6522 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6523 | <input type="checkbox" name="matchCharacterPersonality" /> | ||
| 6524 | <span data-i18n="Character Personality"> | ||
| 6525 | Character Personality | ||
| 6526 | </span> | ||
| 6527 | </label> | ||
| 6528 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6529 | <input type="checkbox" name="matchScenario" /> | ||
| 6530 | <span data-i18n="Scenario"> | ||
| 6531 | Scenario | ||
| 6532 | </span> | ||
| 6533 | </label> | ||
| 6534 | </small> | ||
| 6535 | <small class="flex-container flex1 flexFlowColumn"> | ||
| 6536 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6537 | <input type="checkbox" name="matchPersonaDescription" /> | ||
| 6538 | <span data-i18n="Persona Description"> | ||
| 6539 | Persona Description | ||
| 6540 | </span> | ||
| 6541 | </label> | ||
| 6542 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6543 | <input type="checkbox" name="matchCharacterDepthPrompt" /> | ||
| 6544 | <span data-i18n="Character's Note"> | ||
| 6545 | Character's Note | ||
| 6546 | </span> | ||
| 6547 | </label> | ||
| 6548 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6549 | <input type="checkbox" name="matchCreatorNotes" /> | ||
| 6550 | <span data-i18n="Creator's Notes"> | ||
| 6551 | Creator's Notes | ||
| 6552 | </span> | ||
| 6553 | </label> | ||
| 6554 | </small> | ||
| 6555 | </div> | ||
| 6556 | </div> | ||
| 6557 | </div> | ||
| 6089 | <div class="world_entry"> | 6558 | <div class="world_entry"> |
| 6090 | <form class="world_entry_form wi-card-entry"> | 6559 | <form class="world_entry_form wi-card-entry"> |
| 6091 | <div class="inline-drawer wide100p"> | 6560 | <div class="inline-drawer wide100p"> |
| @@ -6158,297 +6627,8 @@ | |||
| 6158 | <i class="menu_button duplicate_entry_button fa-solid fa-paste" title="Duplicate world info entry" data-i18n="[title]Duplicate world info entry" type="submit" value=""></i> | 6627 | <i class="menu_button duplicate_entry_button fa-solid fa-paste" title="Duplicate world info entry" data-i18n="[title]Duplicate world info entry" type="submit" value=""></i> |
| 6159 | <i class="menu_button delete_entry_button fa-solid fa-trash-can" title="Delete world info entry" data-i18n="[title]Delete world info entry" type="submit" value=""></i> | 6628 | <i class="menu_button delete_entry_button fa-solid fa-trash-can" title="Delete world info entry" data-i18n="[title]Delete world info entry" type="submit" value=""></i> |
| 6160 | </div> | 6629 | </div> |
| 6161 | <div class="inline-drawer-content flex-container paddingBottom5px wide100p"> | 6630 | <div class="inline-drawer-content inline-drawer-outlet flex-container paddingBottom5px wide100p "> |
| 6162 | <div class="flex-container wide100p alignitemscenter"> | 6631 | <!-- Outlet for world_entry_edit --> |
| 6163 | <div name="keywordsAndLogicBlock" class="flex-container wide100p alignitemscenter"> | ||
| 6164 | <div class="world_entry_form_control keyprimary flex1"> | ||
| 6165 | <small class="displayNone"> | ||
| 6166 | <span data-i18n="Comma separated (required)"> | ||
| 6167 | Comma separated (required) | ||
| 6168 | </span> | ||
| 6169 | </small> | ||
| 6170 | <small class="textAlignCenter" data-i18n="Primary Keywords">Primary Keywords</small> | ||
| 6171 | <select class="keyprimaryselect keyselect select2_multi_sameline" name="key" data-i18n="[placeholder]Keywords or Regexes" placeholder="Keywords or Regexes" multiple="multiple"></select> | ||
| 6172 | <textarea class="text_pole keyprimarytextpole mobile" name="key" rows="1" data-i18n="[placeholder]Comma separated list" placeholder="Comma separated list" style="display: none;"></textarea> | ||
| 6173 | <button type="button" class="switch_input_type_icon" tabindex="-1" title="Switch to plaintext mode" data-i18n="[title]Switch to plaintext mode" data-icon-on="✨" data-icon-off="⌨️" data-tooltip-on="Switch to fancy mode" data-tooltip-off="Switch to plaintext mode"> | ||
| 6174 | ⌨️ | ||
| 6175 | </button> | ||
| 6176 | </div> | ||
| 6177 | <div class="world_entry_form_control"> | ||
| 6178 | <small class="textAlignCenter" data-i18n="Logic">Logic</small> | ||
| 6179 | <select name="entryLogicType" class="text_pole widthFitContent margin0"> | ||
| 6180 | <option value="0" data-i18n="AND ANY">AND ANY</option> | ||
| 6181 | <option value="3" data-i18n="AND ALL">AND ALL</option> | ||
| 6182 | <option value="1" data-i18n="NOT ALL">NOT ALL</option> | ||
| 6183 | <option value="2" data-i18n="NOT ANY">NOT ANY</option> | ||
| 6184 | </select> | ||
| 6185 | </div> | ||
| 6186 | <div class="world_entry_form_control keysecondary flex1"> | ||
| 6187 | <small class="displayNone"> | ||
| 6188 | <span data-i18n="(ignored if empty)"> | ||
| 6189 | (ignored if empty) | ||
| 6190 | </span> | ||
| 6191 | </small> | ||
| 6192 | <small class="textAlignCenter" data-i18n="Optional Filter">Optional Filter</small> | ||
| 6193 | <select class="keysecondaryselect keyselect select2_multi_sameline" name="keysecondary" data-i18n="[placeholder]Keywords or Regexes (ignored if empty)" placeholder="Keywords or Regexes (ignored if empty)" multiple="multiple"></select> | ||
| 6194 | <textarea class="text_pole keysecondarytextpole mobile" name="keysecondary" rows="1" data-i18n="[placeholder]Comma separated list (ignored if empty)" placeholder="Comma separated list (ignored if empty)" style="display: none;"></textarea> | ||
| 6195 | <button type="button" class="switch_input_type_icon" tabindex="-1" title="Switch to plaintext mode" data-i18n="[title]Switch to plaintext mode" data-icon-on="✨" data-icon-off="⌨️" data-tooltip-on="Switch to fancy mode" data-tooltip-off="Switch to plaintext mode"> | ||
| 6196 | ⌨️ | ||
| 6197 | </button> | ||
| 6198 | </div> | ||
| 6199 | </div> | ||
| 6200 | <div name="perEntryOverridesBlock" class="flex-container wide100p alignitemscenter"> | ||
| 6201 | <div class="world_entry_form_control flex1"> | ||
| 6202 | <small class="textAlignCenter" data-i18n="Scan Depth">Scan Depth</small> | ||
| 6203 | <input class="text_pole margin0" name="scanDepth" type="number" placeholder="Use global setting" data-i18n="[placeholder]Use global setting" max="1000"> | ||
| 6204 | </div> | ||
| 6205 | <div class="world_entry_form_control flex1"> | ||
| 6206 | <small class="textAlignCenter" data-i18n="Case-Sensitive">Case-Sensitive</small> | ||
| 6207 | <select name="caseSensitive" class="text_pole widthNatural margin0"> | ||
| 6208 | <option value="null" data-i18n="Use global">Use global</option> | ||
| 6209 | <option value="true" data-i18n="Yes">Yes</option> | ||
| 6210 | <option value="false" data-i18n="No">No</option> | ||
| 6211 | </select> | ||
| 6212 | </div> | ||
| 6213 | <div class="world_entry_form_control flex1"> | ||
| 6214 | <small class="textAlignCenter" data-i18n="Whole Words">Whole Words</small> | ||
| 6215 | <select name="matchWholeWords" class="text_pole widthNatural margin0"> | ||
| 6216 | <option value="null" data-i18n="Use global">Use global</option> | ||
| 6217 | <option value="true" data-i18n="Yes">Yes</option> | ||
| 6218 | <option value="false" data-i18n="No">No</option> | ||
| 6219 | </select> | ||
| 6220 | </div> | ||
| 6221 | <div class="world_entry_form_control flex1"> | ||
| 6222 | <small class="textAlignCenter" data-i18n="Group Scoring">Group Scoring</small> | ||
| 6223 | <select name="useGroupScoring" class="text_pole widthNatural margin0"> | ||
| 6224 | <option value="null" data-i18n="Use global">Use global</option> | ||
| 6225 | <option value="true" data-i18n="Yes">Yes</option> | ||
| 6226 | <option value="false" data-i18n="No">No</option> | ||
| 6227 | </select> | ||
| 6228 | </div> | ||
| 6229 | <div class="world_entry_form_control flex1" title="Can be used to automatically activate Quick Replies" data-i18n="[title]Can be used to automatically activate Quick Replies"> | ||
| 6230 | <small class="textAlignCenter" data-i18n="Automation ID">Automation ID</small> | ||
| 6231 | <input class="text_pole margin0" name="automationId" type="text" placeholder="( None )" data-i18n="[placeholder]( None )"> | ||
| 6232 | </div> | ||
| 6233 | <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"> | ||
| 6234 | <small class="textAlignCenter"> | ||
| 6235 | <span data-i18n="Recursion Level">Recursion Level</span> | ||
| 6236 | <div class="fa-solid fa-circle-info opacity50p"></div> | ||
| 6237 | </small> | ||
| 6238 | <input class="text_pole margin0" name="delayUntilRecursionLevel" type="text" placeholder="1"> | ||
| 6239 | </div> | ||
| 6240 | </div> | ||
| 6241 | <div name="contentAndCharFilterBlock" class="world_entry_thin_controls flex2"> | ||
| 6242 | <div class="world_entry_form_control flex1"> | ||
| 6243 | <label for="content "> | ||
| 6244 | <small> | ||
| 6245 | <span class="alignitemscenter flex-container flexnowrap wide100p justifySpaceBetween"> | ||
| 6246 | <span class="alignitemscenter flex-container"> | ||
| 6247 | <span data-i18n="Content" class="mdhotkey_location"> | ||
| 6248 | Content | ||
| 6249 | </span> | ||
| 6250 | <i class="editor_maximize fa-solid fa-maximize right_menu_button" title="Expand the editor" data-i18n="[title]Expand the editor"></i> | ||
| 6251 | </span> | ||
| 6252 | <span> | ||
| 6253 | (<span data-i18n="extension_token_counter">Tokens:</span> <span class="world_entry_form_token_counter" data-first-run="true">counting...</span>) | ||
| 6254 | <span class="world_entry_form_uid_value" data-first-run="true"></span> | ||
| 6255 | </span> | ||
| 6256 | <div> | ||
| 6257 | <label class="checkbox flex-container alignitemscenter flexNoGap"> | ||
| 6258 | <input type="checkbox" name="exclude_recursion" /> | ||
| 6259 | <span data-i18n="Non-recursable (will not be activated by another)"> | ||
| 6260 | Non-recursable (will not be activated by another) | ||
| 6261 | </span> | ||
| 6262 | </label> | ||
| 6263 | <label class="checkbox flex-container alignitemscenter flexNoGap"> | ||
| 6264 | <input type="checkbox" name="prevent_recursion" /> | ||
| 6265 | <span data-i18n="Prevent further recursion (this entry will not activate others)"> | ||
| 6266 | Prevent further recursion (will not activate others) | ||
| 6267 | </span> | ||
| 6268 | </label> | ||
| 6269 | <label class="checkbox flex-container alignitemscenter flexNoGap"> | ||
| 6270 | <input type="checkbox" name="delay_until_recursion" /> | ||
| 6271 | <span data-i18n="Delay until recursion (can only be activated on recursive checking)"> | ||
| 6272 | Delay until recursion (can only be activated on recursive checking) | ||
| 6273 | </span> | ||
| 6274 | </label> | ||
| 6275 | </div> | ||
| 6276 | </span> | ||
| 6277 | </small> | ||
| 6278 | <small class="displayNone"> | ||
| 6279 | <span data-i18n="What this keyword should mean to the AI, sent verbatim"> | ||
| 6280 | What this keyword should mean to the AI, sent verbatim | ||
| 6281 | </span> | ||
| 6282 | </small> | ||
| 6283 | </label> | ||
| 6284 | <textarea class="text_pole mdHotkeys" name="content" rows="8" data-i18n="[placeholder]What this keyword should mean to the AI, sent verbatim" placeholder="What this keyword should mean to the AI, sent verbatim"></textarea> | ||
| 6285 | </div> | ||
| 6286 | </div> | ||
| 6287 | <div class="world_entry_thin_controls commentContainer"> | ||
| 6288 | </div> | ||
| 6289 | </div> | ||
| 6290 | <div class="flex-container wide100p flexGap10"> | ||
| 6291 | <div class="flex4 flex-container flexFlowColumn flexNoGap"> | ||
| 6292 | <div class="flex-container justifySpaceBetween"> | ||
| 6293 | <small for="group"> | ||
| 6294 | <span data-i18n="Inclusion Group">Inclusion Group</span> | ||
| 6295 | <a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/#inclusion-group" class="notes-link" target="_blank" title="Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered. Supports multiple comma-separated groups. Documentation: World Info - Inclusion Group" data-i18n="[title]Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group"> | ||
| 6296 | <span class="fa-solid fa-circle-question note-link-span"></span> | ||
| 6297 | </a> | ||
| 6298 | </small> | ||
| 6299 | <label class="checkbox_label flexNoGap margin-r5" for="groupOverride"> | ||
| 6300 | <input type="checkbox" name="groupOverride" /> | ||
| 6301 | <span> | ||
| 6302 | <small title="Prioritize this entry: When checked, this entry is prioritized out of all selections. If multiple are prioritized, the one with the highest 'Order' is chosen. " data-i18n="[title]Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen."> | ||
| 6303 | <span data-i18n="Prioritize">Prioritize</span> | ||
| 6304 | <div class="fa-solid fa-circle-info opacity50p"></div> | ||
| 6305 | </small> | ||
| 6306 | </span> | ||
| 6307 | </label> | ||
| 6308 | </div> | ||
| 6309 | <div class="range-block-range"> | ||
| 6310 | <input type="text" class="text_pole margin0" name="group" rows="1" data-i18n="[placeholder]Only one entry with the same label will be activated" placeholder="Only one entry with the same label will be activated"> | ||
| 6311 | </div> | ||
| 6312 | </div> | ||
| 6313 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]A relative likelihood of entry activation within the group" title="A relative likelihood of entry activation within the group"> | ||
| 6314 | <div class="flex-container justifySpaceBetween marginBot5"> | ||
| 6315 | <small for="groupWeight" data-i18n="Group Weight"> | ||
| 6316 | Group Weight | ||
| 6317 | </small> | ||
| 6318 | </div> | ||
| 6319 | <div class="range-block-range"> | ||
| 6320 | <input type="number" class="text_pole margin0" name="groupWeight" rows="1" placeholder="100" min="1" max="999999"> | ||
| 6321 | </div> | ||
| 6322 | </div> | ||
| 6323 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Sticky entries will stay active for N messages after being triggered." title="Sticky entries will stay active for N messages after being triggered."> | ||
| 6324 | <div class="flex-container justifySpaceBetween marginBot5"> | ||
| 6325 | <small class="flex-container alignItemsBaseline" for="sticky"> | ||
| 6326 | <span data-i18n="Sticky"> | ||
| 6327 | Sticky | ||
| 6328 | </span> | ||
| 6329 | <i class="fa-solid fa-comments fa-xs"></i> | ||
| 6330 | </small> | ||
| 6331 | </div> | ||
| 6332 | <div class="range-block-range"> | ||
| 6333 | <input class="text_pole margin0" name="sticky" type="number" data-i18n="[placeholder]Non-sticky" placeholder="Non-sticky" min="0" max="999999"> | ||
| 6334 | </div> | ||
| 6335 | </div> | ||
| 6336 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a cooldown can't be activated N messages after being triggered." title="Entries with a cooldown can't be activated N messages after being triggered."> | ||
| 6337 | <div class="flex-container justifySpaceBetween marginBot5"> | ||
| 6338 | <small class="flex-container alignItemsBaseline" for="cooldown"> | ||
| 6339 | <span data-i18n="Cooldown"> | ||
| 6340 | Cooldown | ||
| 6341 | </span> | ||
| 6342 | <i class="fa-solid fa-comments fa-xs"></i> | ||
| 6343 | </small> | ||
| 6344 | </div> | ||
| 6345 | <div class="range-block-range"> | ||
| 6346 | <input class="text_pole margin0" name="cooldown" type="number" data-i18n="[placeholder]No cooldown" placeholder="No cooldown" min="0" max="999999"> | ||
| 6347 | </div> | ||
| 6348 | </div> | ||
| 6349 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a delay can't be activated until there are N messages present in the chat." title="Entries with a delay can't be activated until there are N messages present in the chat."> | ||
| 6350 | <div class="flex-container justifySpaceBetween marginBot5"> | ||
| 6351 | <small class="flex-container alignItemsBaseline" for="delay"> | ||
| 6352 | <span data-i18n="Delay"> | ||
| 6353 | Delay | ||
| 6354 | </span> | ||
| 6355 | <i class="fa-solid fa-comments fa-xs"></i> | ||
| 6356 | </small> | ||
| 6357 | </div> | ||
| 6358 | <div class="range-block-range"> | ||
| 6359 | <input class="text_pole margin0" name="delay" type="number" data-i18n="[placeholder]No delay" placeholder="No delay" min="0" max="999999"> | ||
| 6360 | </div> | ||
| 6361 | </div> | ||
| 6362 | </div> | ||
| 6363 | <div class="flex-container wide100p flexGap10"> | ||
| 6364 | <div class="flex4 flex-container flexFlowColumn flexNoGap"> | ||
| 6365 | <div class="flex-container justifySpaceBetween"> | ||
| 6366 | <small for="characterFilter" data-i18n="Filter to Characters or Tags"> | ||
| 6367 | Filter to Characters or Tags | ||
| 6368 | </small> | ||
| 6369 | <label class="checkbox_label flexNoGap margin-r5" for="character_exclusion"> | ||
| 6370 | <input type="checkbox" name="character_exclusion" /> | ||
| 6371 | <span> | ||
| 6372 | <small title="Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry" data-i18n="[title]Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry"> | ||
| 6373 | <span data-i18n="Exclude">Exclude</span> | ||
| 6374 | <div class="fa-solid fa-circle-info opacity50p"></div> | ||
| 6375 | </small> | ||
| 6376 | </span> | ||
| 6377 | </label> | ||
| 6378 | </div> | ||
| 6379 | <div class="range-block-range"> | ||
| 6380 | <select name="characterFilter" class="select2_multi_sameline" multiple> | ||
| 6381 | <option value="" data-i18n="-- Characters not found --"> | ||
| 6382 | -- Characters not found -- | ||
| 6383 | </option> | ||
| 6384 | </select> | ||
| 6385 | </div> | ||
| 6386 | </div> | ||
| 6387 | </div> | ||
| 6388 | <div name="WIEntryBottomControls" class="flex-container flex1 justifySpaceBetween world_entry_form_horizontal"> | ||
| 6389 | <div class="flex-container flexFlowColumn flexNoGap wi-enter-footer-text "> | ||
| 6390 | <label class="checkbox flex-container"> | ||
| 6391 | <input type="checkbox" name="selective" /> | ||
| 6392 | <span data-i18n="Selective">Selective</span> | ||
| 6393 | </label> | ||
| 6394 | <label class="checkbox flex-container"> | ||
| 6395 | <input type="checkbox" name="useProbability" /> | ||
| 6396 | <span data-i18n="Use Probability">Use Probability</span> | ||
| 6397 | </label> | ||
| 6398 | <label class="checkbox flex-container"> | ||
| 6399 | <input type="checkbox" name="addMemo"> | ||
| 6400 | <span data-i18n="Add Memo">Add Memo</span> | ||
| 6401 | </label> | ||
| 6402 | </div> | ||
| 6403 | </div> | ||
| 6404 | <div class="inline-drawer wide100p flexFlowColumn"> | ||
| 6405 | <div class="inline-drawer-toggle inline-drawer-header inline-drawer-header-pointer userSettingsInnerExpandable"> | ||
| 6406 | <strong data-i18n="Additional Matching Sources">Additional Matching Sources</strong> | ||
| 6407 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | ||
| 6408 | </div> | ||
| 6409 | <div class="inline-drawer-content flex-container flexFlowRow flexGap10 paddingBottom5px"> | ||
| 6410 | <small class="flex-container flex1 flexFlowColumn"> | ||
| 6411 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6412 | <input type="checkbox" name="matchCharacterDescription" /> | ||
| 6413 | <span data-i18n="Character Description"> | ||
| 6414 | Character Description | ||
| 6415 | </span> | ||
| 6416 | </label> | ||
| 6417 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6418 | <input type="checkbox" name="matchCharacterPersonality" /> | ||
| 6419 | <span data-i18n="Character Personality"> | ||
| 6420 | Character Personality | ||
| 6421 | </span> | ||
| 6422 | </label> | ||
| 6423 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6424 | <input type="checkbox" name="matchScenario" /> | ||
| 6425 | <span data-i18n="Scenario"> | ||
| 6426 | Scenario | ||
| 6427 | </span> | ||
| 6428 | </label> | ||
| 6429 | </small> | ||
| 6430 | <small class="flex-container flex1 flexFlowColumn"> | ||
| 6431 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6432 | <input type="checkbox" name="matchPersonaDescription" /> | ||
| 6433 | <span data-i18n="Persona Description"> | ||
| 6434 | Persona Description | ||
| 6435 | </span> | ||
| 6436 | </label> | ||
| 6437 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6438 | <input type="checkbox" name="matchCharacterDepthPrompt" /> | ||
| 6439 | <span data-i18n="Character's Note"> | ||
| 6440 | Character's Note | ||
| 6441 | </span> | ||
| 6442 | </label> | ||
| 6443 | <label class="checkbox flex-container alignItemsCenter flexNoGap"> | ||
| 6444 | <input type="checkbox" name="matchCreatorNotes" /> | ||
| 6445 | <span data-i18n="Creator's Notes"> | ||
| 6446 | Creator's Notes | ||
| 6447 | </span> | ||
| 6448 | </label> | ||
| 6449 | </small> | ||
| 6450 | </div> | ||
| 6451 | </div> | ||
| 6452 | </div> | 6632 | </div> |
| 6453 | </div> | 6633 | </div> |
| 6454 | </form> | 6634 | </form> |
| @@ -6587,7 +6767,6 @@ | |||
| 6587 | <span id="completion_prompt_manager_popup_entry_source"></span> | 6767 | <span id="completion_prompt_manager_popup_entry_source"></span> |
| 6588 | </div> | 6768 | </div> |
| 6589 | <textarea id="completion_prompt_manager_popup_entry_form_prompt" class="text_pole" name="prompt" placeholder="The prompt to be sent." data-i18n="[placeholder]The prompt to be sent."></textarea> | 6769 | <textarea id="completion_prompt_manager_popup_entry_form_prompt" class="text_pole" name="prompt" placeholder="The prompt to be sent." data-i18n="[placeholder]The prompt to be sent."></textarea> |
| 6590 | </textarea> | ||
| 6591 | </div> | 6770 | </div> |
| 6592 | <div class="completion_prompt_manager_popup_entry_form_footer"> | 6771 | <div class="completion_prompt_manager_popup_entry_form_footer"> |
| 6593 | <a id="completion_prompt_manager_popup_entry_form_close" title="close" data-i18n="[title]close" class="fa-solid fa-close menu_button"></a> | 6772 | <a id="completion_prompt_manager_popup_entry_form_close" title="close" data-i18n="[title]close" class="fa-solid fa-close menu_button"></a> |
| @@ -7347,6 +7526,9 @@ | |||
| 7347 | </div> | 7526 | </div> |
| 7348 | </div> | 7527 | </div> |
| 7349 | 7528 | ||
| 7529 | <!-- Area for hidden data lists for secrets autosuggests --> | ||
| 7530 | <div id="secrets_datalists" class="displayNone"></div> | ||
| 7531 | |||
| 7350 | <!-- Script includes --> | 7532 | <!-- Script includes --> |
| 7351 | <script src="lib/polyfill.js"></script> | 7533 | <script src="lib/polyfill.js"></script> |
| 7352 | <script src="lib/jquery-3.5.1.min.js"></script> | 7534 | <script src="lib/jquery-3.5.1.min.js"></script> |
| @@ -1379,6 +1379,7 @@ | |||
| 1379 | "char_import_6": "رابط PNG المباشر (راجع", | 1379 | "char_import_6": "رابط PNG المباشر (راجع", |
| 1380 | "char_import_7": "للمضيفين المسموح بهم)", | 1380 | "char_import_7": "للمضيفين المسموح بهم)", |
| 1381 | "char_import_8": "شخصية RisuRealm (رابط مباشر)", | 1381 | "char_import_8": "شخصية RisuRealm (رابط مباشر)", |
| 1382 | "char_import_9": "شخصية Soulkyn (رابط مباشر)", | ||
| 1382 | "Supports importing multiple characters.": "يدعم استيراد أحرف متعددة.", | 1383 | "Supports importing multiple characters.": "يدعم استيراد أحرف متعددة.", |
| 1383 | "Write each URL or ID into a new line.": "اكتب كل عنوان URL أو معرف في سطر جديد.", | 1384 | "Write each URL or ID into a new line.": "اكتب كل عنوان URL أو معرف في سطر جديد.", |
| 1384 | "Export for character": "تصدير للشخصية", | 1385 | "Export for character": "تصدير للشخصية", |
| @@ -1379,6 +1379,7 @@ | |||
| 1379 | "char_import_6": "Direkter PNG-Link (siehe", | 1379 | "char_import_6": "Direkter PNG-Link (siehe", |
| 1380 | "char_import_7": "für erlaubte Hosts)", | 1380 | "char_import_7": "für erlaubte Hosts)", |
| 1381 | "char_import_8": "RisuRealm-Charakter (Direktlink)", | 1381 | "char_import_8": "RisuRealm-Charakter (Direktlink)", |
| 1382 | "char_import_9": "Soulkyn-Charakter (Direktlink)", | ||
| 1382 | "Supports importing multiple characters.": "Unterstützt den Import mehrerer Zeichen.", | 1383 | "Supports importing multiple characters.": "Unterstützt den Import mehrerer Zeichen.", |
| 1383 | "Write each URL or ID into a new line.": "Schreiben Sie jede URL oder ID in eine neue Zeile.", | 1384 | "Write each URL or ID into a new line.": "Schreiben Sie jede URL oder ID in eine neue Zeile.", |
| 1384 | "Export for character": "Export für Zeichen", | 1385 | "Export for character": "Export für Zeichen", |
| @@ -1379,6 +1379,7 @@ | |||
| 1379 | "char_import_6": "Enlace PNG directo (consulte", | 1379 | "char_import_6": "Enlace PNG directo (consulte", |
| 1380 | "char_import_7": "para hosts permitidos)", | 1380 | "char_import_7": "para hosts permitidos)", |
| 1381 | "char_import_8": "Personaje RisuRealm (Enlace directo)", | 1381 | "char_import_8": "Personaje RisuRealm (Enlace directo)", |
| 1382 | "char_import_9": "Personaje Soulkyn (Enlace directo)", | ||
| 1382 | "Supports importing multiple characters.": "Admite la importación de múltiples caracteres.", | 1383 | "Supports importing multiple characters.": "Admite la importación de múltiples caracteres.", |
| 1383 | "Write each URL or ID into a new line.": "Escriba cada URL o ID en una nueva línea.", | 1384 | "Write each URL or ID into a new line.": "Escriba cada URL o ID en una nueva línea.", |
| 1384 | "Export for character": "Exportar para personaje", | 1385 | "Export for character": "Exportar para personaje", |
| @@ -1301,6 +1301,7 @@ | |||
| 1301 | "char_import_6": "Lien PNG direct (voir", | 1301 | "char_import_6": "Lien PNG direct (voir", |
| 1302 | "char_import_7": "pour les hôtes autorisés)", | 1302 | "char_import_7": "pour les hôtes autorisés)", |
| 1303 | "char_import_8": "Personnage de RisuRealm (lien direct)", | 1303 | "char_import_8": "Personnage de RisuRealm (lien direct)", |
| 1304 | "char_import_9": "Personnage de Soulkyn (lien direct)", | ||
| 1304 | "Supports importing multiple characters.": "Prend en charge l'importation de plusieurs caractères.", | 1305 | "Supports importing multiple characters.": "Prend en charge l'importation de plusieurs caractères.", |
| 1305 | "Write each URL or ID into a new line.": "Écrivez chaque URL ou identifiant dans une nouvelle ligne.", | 1306 | "Write each URL or ID into a new line.": "Écrivez chaque URL ou identifiant dans une nouvelle ligne.", |
| 1306 | "Export for character": "Exportation pour le personnage", | 1307 | "Export for character": "Exportation pour le personnage", |
| @@ -1379,6 +1379,7 @@ | |||
| 1379 | "char_import_6": "Beinn PNG hlekkur (sjá", | 1379 | "char_import_6": "Beinn PNG hlekkur (sjá", |
| 1380 | "char_import_7": "fyrir leyfilega gestgjafa)", | 1380 | "char_import_7": "fyrir leyfilega gestgjafa)", |
| 1381 | "char_import_8": "RisuRealm karakter (beinn hlekkur)", | 1381 | "char_import_8": "RisuRealm karakter (beinn hlekkur)", |
| 1382 | "char_import_9": "Soulkyn karakter (beinn hlekkur)", | ||
| 1382 | "Supports importing multiple characters.": "Styður innflutning á mörgum stöfum.", | 1383 | "Supports importing multiple characters.": "Styður innflutning á mörgum stöfum.", |
| 1383 | "Write each URL or ID into a new line.": "Skrifaðu hverja vefslóð eða auðkenni í nýja línu.", | 1384 | "Write each URL or ID into a new line.": "Skrifaðu hverja vefslóð eða auðkenni í nýja línu.", |
| 1384 | "Export for character": "Flytja út fyrir persónu", | 1385 | "Export for character": "Flytja út fyrir persónu", |
| @@ -1379,6 +1379,7 @@ | |||
| 1379 | "char_import_6": "Collegamento PNG diretto (fare riferimento a", | 1379 | "char_import_6": "Collegamento PNG diretto (fare riferimento a", |
| 1380 | "char_import_7": "per gli host consentiti)", | 1380 | "char_import_7": "per gli host consentiti)", |
| 1381 | "char_import_8": "Personaggio RisuRealm (collegamento diretto)", | 1381 | "char_import_8": "Personaggio RisuRealm (collegamento diretto)", |
| 1382 | "char_import_9": "Personaggio Soulkyn (collegamento diretto)", | ||
| 1382 | "Supports importing multiple characters.": "Supporta l'importazione di più caratteri.", | 1383 | "Supports importing multiple characters.": "Supporta l'importazione di più caratteri.", |
| 1383 | "Write each URL or ID into a new line.": "Scrivi ogni URL o ID in una nuova riga.", | 1384 | "Write each URL or ID into a new line.": "Scrivi ogni URL o ID in una nuova riga.", |
| 1384 | "Export for character": "Esporta per carattere", | 1385 | "Export for character": "Esporta per carattere", |
| @@ -1381,6 +1381,7 @@ | |||
| 1381 | "char_import_6": "直接PNGリンク(参照", | 1381 | "char_import_6": "直接PNGリンク(参照", |
| 1382 | "char_import_7": "許可されたホストの場合)", | 1382 | "char_import_7": "許可されたホストの場合)", |
| 1383 | "char_import_8": "RisuRealm キャラクター (直接リンク)", | 1383 | "char_import_8": "RisuRealm キャラクター (直接リンク)", |
| 1384 | "char_import_9": "Soulkyn キャラクター (直接リンク)", | ||
| 1384 | "Supports importing multiple characters.": "複数のキャラクターのインポートをサポートします。", | 1385 | "Supports importing multiple characters.": "複数のキャラクターのインポートをサポートします。", |
| 1385 | "Write each URL or ID into a new line.": "各 URL または ID を新しい行に入力します。", | 1386 | "Write each URL or ID into a new line.": "各 URL または ID を新しい行に入力します。", |
| 1386 | "Export for character": "キャラクターのエクスポート", | 1387 | "Export for character": "キャラクターのエクスポート", |
| @@ -1398,6 +1398,7 @@ | |||
| 1398 | "char_import_6": "직접 PNG 링크(참조", | 1398 | "char_import_6": "직접 PNG 링크(참조", |
| 1399 | "char_import_7": "허용된 호스트의 경우)", | 1399 | "char_import_7": "허용된 호스트의 경우)", |
| 1400 | "char_import_8": "RisuRealm 캐릭터 (직접링크)", | 1400 | "char_import_8": "RisuRealm 캐릭터 (직접링크)", |
| 1401 | "char_import_9": "Soulkyn 캐릭터 (직접링크)", | ||
| 1401 | "Supports importing multiple characters.": "여러 문자 가져오기를 지원합니다.", | 1402 | "Supports importing multiple characters.": "여러 문자 가져오기를 지원합니다.", |
| 1402 | "Write each URL or ID into a new line.": "각 URL 또는 ID를 새 줄에 작성합니다.", | 1403 | "Write each URL or ID into a new line.": "각 URL 또는 ID를 새 줄에 작성합니다.", |
| 1403 | "Export for character": "캐릭터 내보내기", | 1404 | "Export for character": "캐릭터 내보내기", |
| @@ -1379,6 +1379,7 @@ | |||
| 1379 | "char_import_6": "Directe PNG-link (zie", | 1379 | "char_import_6": "Directe PNG-link (zie", |
| 1380 | "char_import_7": "voor toegestane hosts)", | 1380 | "char_import_7": "voor toegestane hosts)", |
| 1381 | "char_import_8": "RisuRealm-personage (directe link)", | 1381 | "char_import_8": "RisuRealm-personage (directe link)", |
| 1382 | "char_import_9": "Soulkyn-personage (directe link)", | ||
| 1382 | "Supports importing multiple characters.": "Ondersteunt het importeren van meerdere tekens.", | 1383 | "Supports importing multiple characters.": "Ondersteunt het importeren van meerdere tekens.", |
| 1383 | "Write each URL or ID into a new line.": "Schrijf elke URL of ID op een nieuwe regel.", | 1384 | "Write each URL or ID into a new line.": "Schrijf elke URL of ID op een nieuwe regel.", |
| 1384 | "Export for character": "Exporteren voor karakter", | 1385 | "Export for character": "Exporteren voor karakter", |
| @@ -1379,6 +1379,7 @@ | |||
| 1379 | "char_import_6": "Link PNG direto (consulte", | 1379 | "char_import_6": "Link PNG direto (consulte", |
| 1380 | "char_import_7": "para hosts permitidos)", | 1380 | "char_import_7": "para hosts permitidos)", |
| 1381 | "char_import_8": "Personagem RisuRealm (link direto)", | 1381 | "char_import_8": "Personagem RisuRealm (link direto)", |
| 1382 | "char_import_9": "Personagem Soulkyn (link direto)", | ||
| 1382 | "Supports importing multiple characters.": "Suporta importação de vários caracteres.", | 1383 | "Supports importing multiple characters.": "Suporta importação de vários caracteres.", |
| 1383 | "Write each URL or ID into a new line.": "Escreva cada URL ou ID em uma nova linha.", | 1384 | "Write each URL or ID into a new line.": "Escreva cada URL ou ID em uma nova linha.", |
| 1384 | "Export for character": "Exportar para personagem", | 1385 | "Export for character": "Exportar para personagem", |
| @@ -105,7 +105,7 @@ | |||
| 105 | "Adjust context size to worker capabilities": "Подстраивать размер контекста под возможности рабочих машин", | 105 | "Adjust context size to worker capabilities": "Подстраивать размер контекста под возможности рабочих машин", |
| 106 | "Adjust response length to worker capabilities": "Подстраивать длину ответа под возможности рабочих машин", | 106 | "Adjust response length to worker capabilities": "Подстраивать длину ответа под возможности рабочих машин", |
| 107 | "API key": "API-ключ", | 107 | "API key": "API-ключ", |
| 108 | "Tabby API key": "Tabby API-ключ", | 108 | "Tabby API key": "Ключ от Tabby API", |
| 109 | "Get it here:": "Получите здесь:", | 109 | "Get it here:": "Получите здесь:", |
| 110 | "Register": "Зарегистрироваться", | 110 | "Register": "Зарегистрироваться", |
| 111 | "TogetherAI Model": "Модель TogetherAI", | 111 | "TogetherAI Model": "Модель TogetherAI", |
| @@ -275,7 +275,7 @@ | |||
| 275 | "Chat History": "История чатов", | 275 | "Chat History": "История чатов", |
| 276 | "Content": "Содержание", | 276 | "Content": "Содержание", |
| 277 | "Selective": "Выборочно", | 277 | "Selective": "Выборочно", |
| 278 | "Disable": "Отключено", | 278 | "Disable": "Откл.", |
| 279 | "Back to parent chat": "Вернуться в основной чат", | 279 | "Back to parent chat": "Вернуться в основной чат", |
| 280 | "Convert to group": "Сделать групповым", | 280 | "Convert to group": "Сделать групповым", |
| 281 | "Start new chat": "Начать новый чат", | 281 | "Start new chat": "Начать новый чат", |
| @@ -509,7 +509,7 @@ | |||
| 509 | "Restore default prompt": "Восстановить станндартный промпт", | 509 | "Restore default prompt": "Восстановить станндартный промпт", |
| 510 | "New preset": "Новый пресет", | 510 | "New preset": "Новый пресет", |
| 511 | "Delete preset": "Удалить пресет", | 511 | "Delete preset": "Удалить пресет", |
| 512 | "API Connections": "Соединения с API", | 512 | "API Connections": "Соединение с API", |
| 513 | "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Может помочь при плохих ответах, делая запросы только к доверенным рабочим машинам. Может замедлить время ответа.", | 513 | "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Может помочь при плохих ответах, делая запросы только к доверенным рабочим машинам. Может замедлить время ответа.", |
| 514 | "Clear your API key": "Стереть ключ от API", | 514 | "Clear your API key": "Стереть ключ от API", |
| 515 | "Refresh models": "Обновить модели", | 515 | "Refresh models": "Обновить модели", |
| @@ -965,6 +965,7 @@ | |||
| 965 | "char_import_5": "Персонаж с AICharacterCards.com (прямая ссылка или ID)", | 965 | "char_import_5": "Персонаж с AICharacterCards.com (прямая ссылка или ID)", |
| 966 | "char_import_6": "Прямая ссылка на PNG-файл (список разрешённых хостов находится в", | 966 | "char_import_6": "Прямая ссылка на PNG-файл (список разрешённых хостов находится в", |
| 967 | "char_import_7": ")", | 967 | "char_import_7": ")", |
| 968 | "char_import_9": "Персонаж с Soulkyn (прямая ссылка)", | ||
| 968 | "Grammar String": "Грамматика", | 969 | "Grammar String": "Грамматика", |
| 969 | "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF или EBNF, зависит от бэкенда. Если вы это используете, то, скорее всего, сами знаете, какой именно.", | 970 | "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF или EBNF, зависит от бэкенда. Если вы это используете, то, скорее всего, сами знаете, какой именно.", |
| 970 | "Account": "Аккаунт", | 971 | "Account": "Аккаунт", |
| @@ -2418,5 +2419,144 @@ | |||
| 2418 | "Update enabled": "Обновить включенные", | 2419 | "Update enabled": "Обновить включенные", |
| 2419 | "Could not connect to API": "Не удалось подключиться к API", | 2420 | "Could not connect to API": "Не удалось подключиться к API", |
| 2420 | "Connected to API": "Соединение с API установлено", | 2421 | "Connected to API": "Соединение с API установлено", |
| 2421 | "Go back": "Назад" | 2422 | "Go back": "Назад", |
| 2423 | "Recent Chats": "Недавние чаты", | ||
| 2424 | "Docs": "Документация", | ||
| 2425 | "Temporary Chat": "Временный чат", | ||
| 2426 | "Load": "Загрузить", | ||
| 2427 | "Import from JSONL": "Импорт из формата JSONL", | ||
| 2428 | "**Hint:** Set any character as your welcome page assistant from their \"More...\" menu.": "**Подсказка**: задайте персонажа, который будет встречать вас на главной странице. Для этого зайдите в меню \"Ещё...\" в интерфейсе карточки.", | ||
| 2429 | "[The chat is empty]": "[Чат пуст]", | ||
| 2430 | "Show more recent chats": "Больше недавних чатов", | ||
| 2431 | "Show less recent chats": "Меньше недавних чатов", | ||
| 2432 | "Rename chat": "Переименовать чат", | ||
| 2433 | "Delete chat": "Удалить чат", | ||
| 2434 | "Hide recent chats": "Скрыть недавние чаты", | ||
| 2435 | "Show recent chats": "Показать недавние чаты", | ||
| 2436 | "Set / Unset as Welcome Page Assistant": "Установить / снять с роли помощника на экране приветствия", | ||
| 2437 | "${0} is a system assistant. Choose another character.": "Персонаж ${0} выбран в качестве системного помощника. Выберите другого.", | ||
| 2438 | "Set ${0} as your assistant.": "Персонаж ${0} установлен в качестве помощника.", | ||
| 2439 | "${0} is no longer your assistant.": "Персонаж ${0} снят с роли помощника.", | ||
| 2440 | "Manage API keys": "Управление ключами", | ||
| 2441 | "Key:": "Ключ:", | ||
| 2442 | "No secrets saved.": "Ключей нет.", | ||
| 2443 | "Add Secret": "Добавить ключ", | ||
| 2444 | "Enter the secret value:": "Ключ:", | ||
| 2445 | "Enter a label for the secret (optional):": "Название ключа (необязательно):", | ||
| 2446 | "Copy ID": "Копировать ID", | ||
| 2447 | "Rename Secret": "Переименовать ключ", | ||
| 2448 | "Enter new label for the secret:": "Новое название ключа:", | ||
| 2449 | "Delete Secret: ${0}": "Удалить ключ ${0}", | ||
| 2450 | "Are you sure you want to delete this secret? This action cannot be undone.": "Вы точно хотите удалить этот ключ? Отменить будет невозможно.", | ||
| 2451 | "Secret ID copied to clipboard.": "ID ключа скопирован в буфер обмена.", | ||
| 2452 | "The key exposure might be disabled by the server config.": "Вероятно, в настройках сервера отключена возможность раскрытия ключей.", | ||
| 2453 | "Failed to copy secret value": "Не удалось скопировать значение", | ||
| 2454 | "Select": "Выделить", | ||
| 2455 | "Allow compressing requests by removing messages from the middle of the prompt.": "Включает возможность сжатия запроса путём удаления сообщений из середины промпта.", | ||
| 2456 | "Allow": "Разрешить", | ||
| 2457 | "Forbid": "Запретить", | ||
| 2458 | "Auto": "Авто", | ||
| 2459 | "Max prompt cost:": "Макс. стоимость промпта:", | ||
| 2460 | "Unknown": "Неизвестно", | ||
| 2461 | "enable_functions_desc_4": "Не работает, если выбрана постобработка промпта с отключенными функциями!", | ||
| 2462 | "This setting affects visibility only.": "Влияет только на видимость.", | ||
| 2463 | "openrouter_web_search_fee": "Платная опция! Добавляет $0,02 к стоимости каждого промпта.", | ||
| 2464 | "prompt_post_processing_semi_tools": "Semi-strict (чередовать роли, функции включены)", | ||
| 2465 | "prompt_post_processing_strict_tools": "Strict (чередовать роли, сначала пользователь; функции включены)", | ||
| 2466 | "prompt_post_processing_single": "Только одно сообщение пользователя (функции отключены)", | ||
| 2467 | "prompt_post_processing_merge_tools": "Объединять идущие подряд сообщение с одной ролью (функции включены)", | ||
| 2468 | "completions note prefix": "Постфикс ", | ||
| 2469 | "suffix will be added automatically.": "будет добавлен автоматически.", | ||
| 2470 | "Tabby Model": "Модель Tabby", | ||
| 2471 | "Experimental feature. Use at your own risk.": "Экспериментальная возможность. Используйте на собственный риск.", | ||
| 2472 | "Tabby model hint prefix": "Чтобы иметь возможность менять модели на лету, укажите параметр ", | ||
| 2473 | "must be set in Tabby's config.yml to switch models.": " в файле config.yml на сервере Tabby.", | ||
| 2474 | "Use an admin API key.": "Используйте admin-ключ.", | ||
| 2475 | "Use OpenRouter website setting": "Использовать указанную на сайте OpenRouter", | ||
| 2476 | "Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking.": "Отводит часть ответа под рассуждения (Минимальные: 10%, Обычные: 25%, Подробные: 50%, Максимальные: 95%), но минимум 1024 токена. При выборе значение Авто рассуждения не запрашиваются.", | ||
| 2477 | "Use system prompt": "Включить системный промпт", | ||
| 2478 | "Send inline videos": "Отправлять inline-видео", | ||
| 2479 | "video_inlining_hint_1": "Отправляет модели видео, если она поддерживает такую возможность. Чтобы прикрепить видео к чату, используйте на любом сообщении кнопку", | ||
| 2480 | "video_inlining_hint_2": "либо меню", | ||
| 2481 | "video_inlining_hint_3": ".", | ||
| 2482 | "video_inlining_hint_4": "Видео должно весить не более 20 Мб и длиться не дольше 1 минуты.", | ||
| 2483 | "Allocates a portion of the response length for thinking (Flash 2.5/Pro 2.5) (min: 0/128 tokens, low: 10%, medium: 25%, high: 50%, max: 24576/32768 tokens). Auto lets the model decide.": "Отводит часть ответа под рассуждения (Flash 2.5/Pro 2.5) (Минимальные: 0/128 токенов, Поверхностные: 10%, Обычные: 25%, Подробные: 50%, Максимальные: 24576/32768 токенов). При выборе значения Авто модель определяет объём самостоятельно.", | ||
| 2484 | "Google Vertex AI Configuration": "Настройки Google Vertex AI", | ||
| 2485 | "Authentication Mode": "Режим аутентификации:", | ||
| 2486 | "Express Mode (API Key)": "Express Mode (ключ от API)", | ||
| 2487 | "Full Version (Service Account)": "Полновесный (аккаунт на сервисе)", | ||
| 2488 | "Google Vertex AI API Key": "Ключ от Google Vertex AI", | ||
| 2489 | "Service Account Configuration": "Настройки аккаунта", | ||
| 2490 | "Region": "Регион", | ||
| 2491 | "Service Account JSON Content": "Данные аккаунта в формате JSON", | ||
| 2492 | "Validate JSON": "Провалидировать JSON", | ||
| 2493 | "View available regions and models": "Посмотреть список доступных регионов и моделей", | ||
| 2494 | "Click to Edit": "Редактирование по клику", | ||
| 2495 | "Click the message text in the chat log to edit it.": "Нажмите на текст сообщения в чате, чтобы приступить к редактированию.", | ||
| 2496 | "Rounded": "Закруглённые", | ||
| 2497 | "Notifications:": "Уведомления:", | ||
| 2498 | "Top Left": "Слева сверху", | ||
| 2499 | "Top Center": "Сверху по центру", | ||
| 2500 | "Top Right": "Справа сверху", | ||
| 2501 | "Bottom Left": "Снизу слева", | ||
| 2502 | "Bottom Center": "Снизу по центру", | ||
| 2503 | "Bottom Right": "Снизу справа", | ||
| 2504 | "Additional Matching Sources": "Доп. места для поиска", | ||
| 2505 | "Character Personality": "Резюме по личности персонажа", | ||
| 2506 | "Cap the number of entry activation recursions": "Макс. глубина рекурсии при активации записи другой записью", | ||
| 2507 | "Animated background thumbnails": "Статичное превью анимированных фонов", | ||
| 2508 | "Make animated backgrounds static in the selection menu. This will reduce UI and network lag if you have a large amount. This is only a change for the selection menu.": "Отключить анимацию фонов при их предпросмотре в меню выбора. Может помочь снизить объём лагов интерфейса и/или интернет-соединения. Затрагивает только меню выбора.", | ||
| 2509 | "Clean-Up": "Уборка", | ||
| 2510 | "Find and delete backups, unused chats, files, images, etc.": "Найти и удалить бэкапы, неиспользуемые чаты, файлы, картинки и т.д.", | ||
| 2511 | "Once deleted, the files will be gone forever!": "Восстановить удалённые файлы будет невозможно!", | ||
| 2512 | "Make sure to back up your data in advance.": "Перед удалением не забывайте делать копии.", | ||
| 2513 | "No results yet. Tap 'Scan' to start scanning.": "Пока ничего не найдено. Нажмите \"Начать сканирование\", чтобы запустить процесс поиска.", | ||
| 2514 | "Scan": "Начать сканирование", | ||
| 2515 | "Chats": "Чаты", | ||
| 2516 | "Chat files associated with deleted characters.": "Чаты с удалёнными персонажами.", | ||
| 2517 | "Group Chats": "Групповые чаты", | ||
| 2518 | "Chat files associated with deleted groups.": "Чаты с удалёнными группами.", | ||
| 2519 | "Chat Backups": "Копии чатов", | ||
| 2520 | "Automatically generated chat backups.": "Автоматически создаваемые бэкапы чатов.", | ||
| 2521 | "Settings Backups": "Копии настроек", | ||
| 2522 | "Automatically generated settings backups.": "Автоматически создаваемые бэкапы настроек.", | ||
| 2523 | "Delete all items in this category": "Удалить всё в этой категории", | ||
| 2524 | "View item content": "Посмотреть содержимое", | ||
| 2525 | "Download item": "Скачать содержимое", | ||
| 2526 | "Delete this item": "Удалить содержимое", | ||
| 2527 | "This will permanently delete the file. THIS CANNOT BE UNDONE!": "Файл будет удалён навсегда. ОТМЕНИТЬ БУДЕТ НЕВОЗМОЖНО!", | ||
| 2528 | "This will permanently delete all files in this category. THIS CANNOT BE UNDONE!": "Все файлы в этой категории будут удалены. ОТМЕНИТЬ БУДЕТ НЕВОЗМОЖНО!", | ||
| 2529 | "Close popup": "Закрыть окно", | ||
| 2530 | "Branch or tag name (optional)": "Ветка или тэг (необязательно)", | ||
| 2531 | "ext_regex_bulk_edit": "Массовое редактирование", | ||
| 2532 | "Enable": "Вкл.", | ||
| 2533 | "Provided free of charge by Pollinations.AI": "Предоставляется бесплатно сервисом Pollinations.AI", | ||
| 2534 | "Avoid sending sensitive information. Provider's outputs may include ads.": "Не отправляйте чувствительную информацию. Тексты от провайдера могут содержать рекламу.", | ||
| 2535 | "Pollinations Model": "Модель Pollinations", | ||
| 2536 | "Character details are hidden.": "Информация о персонаже скрыта.", | ||
| 2537 | "Allow / Forbid the use of global styles for this character.": "Разрешить/запретить использование персонажем глобальных стилей.", | ||
| 2538 | "Choose how to apply CSS style tags if they are defined in Creator's Notes of this character:": "Выберите, к чему применять CSS-теги, объявленные в Заметках создателя у этого персонажа:", | ||
| 2539 | "CAUTION: Malformed styles may cause issues.": "ОСТОРОЖНО: некорректно размеченные стили могут приводить к неожиданному поведению.", | ||
| 2540 | "Just to Creator's Notes": "Только к Заметкам создателя", | ||
| 2541 | "Apply to the entire app": "Ко всему приложению", | ||
| 2542 | "Pin greeting message styles": "CSS из первого сообщения активен всегда", | ||
| 2543 | "Always render style tags from greetings, even if the message is unloaded due to lazy loading.": "Всегда учитывать CSS-стили из первого сообщения, даже если оно на данный момент скрыто механизмом ленивой загрузки.", | ||
| 2544 | "Secret": "Ключ", | ||
| 2545 | "Save and connect": "Сохранить и подключиться", | ||
| 2546 | "No scripts found": "Скриптов нет", | ||
| 2547 | "Are you sure you want to delete this regex script?": "Вы точно хотите удалить этот скрипт?", | ||
| 2548 | "Are you sure you want to move this regex script to scoped?": "Вы точно хотите сделать этот скрипт локальным?", | ||
| 2549 | "Cannot edit scoped scripts in group chats.": "Локальные скрипты невозможно редактировать в групповом чате.", | ||
| 2550 | "No character selected.": "Не выбран персонаж.", | ||
| 2551 | "Are you sure you want to move this regex script to global?": "Вы точно хотите сделать этот скрипт глобальным?", | ||
| 2552 | "Could not save regex script: The script name was undefined or empty!": "Не удалось сохранить regex-скрипт: Не указано либо не определено название скрипта!", | ||
| 2553 | "This regex script will not work, but was saved anyway: A find regex isn't present.": "Этот regex не будет работать, но всё равно сохранён: Не указано рег. выражение для поиска", | ||
| 2554 | "Ephemerality": "Иллюзорность", | ||
| 2555 | "This regex script will not work, but was saved anyway: One \"Affects\" checkbox must be selected!": "Этот regex не будет работать, но всё равно сохранён: Должна быть отмечена хотя бы одна галочка в блоке \"Затрагивает\"!", | ||
| 2556 | "This character has embedded regex script(s).": "У этого персонажа имеются встроенные regex скрипты.", | ||
| 2557 | "Would you like to allow using them?": "Должны ли они продолжать работу?", | ||
| 2558 | "If you want to do it later, select 'Regex' from the extensions menu.": "Если захотите включить их позже, выберите в меню расширений пункт \"Regex\".", | ||
| 2559 | "Are you sure you want to delete the selected regex scripts?": "Вы точно хотите удалить выбранные скрипты?", | ||
| 2560 | "Regex script \"${0}\" imported.": "Успешно импортирован скрипт ${0}", | ||
| 2561 | "Invalid regex object.": "Некорректный объект рег. выражения." | ||
| 2422 | } | 2562 | } |
| @@ -1379,6 +1379,7 @@ | |||
| 1379 | "char_import_6": "Пряме посилання на PNG (див", | 1379 | "char_import_6": "Пряме посилання на PNG (див", |
| 1380 | "char_import_7": "для дозволених хостів)", | 1380 | "char_import_7": "для дозволених хостів)", |
| 1381 | "char_import_8": "Персонаж RisuRealm (пряме посилання)", | 1381 | "char_import_8": "Персонаж RisuRealm (пряме посилання)", |
| 1382 | "char_import_9": "Персонаж Soulkyn (пряме посилання)", | ||
| 1382 | "Supports importing multiple characters.": "Підтримується імпорт кількох символів.", | 1383 | "Supports importing multiple characters.": "Підтримується імпорт кількох символів.", |
| 1383 | "Write each URL or ID into a new line.": "Напишіть кожну URL-адресу або ідентифікатор у новому рядку.", | 1384 | "Write each URL or ID into a new line.": "Напишіть кожну URL-адресу або ідентифікатор у новому рядку.", |
| 1384 | "Export for character": "Експорт для персонажа", | 1385 | "Export for character": "Експорт для персонажа", |
| @@ -1379,6 +1379,7 @@ | |||
| 1379 | "char_import_6": "Nhập PNG trực tiếp (tham khảo", | 1379 | "char_import_6": "Nhập PNG trực tiếp (tham khảo", |
| 1380 | "char_import_7": "đối với các máy chủ được phép)", | 1380 | "char_import_7": "đối với các máy chủ được phép)", |
| 1381 | "char_import_8": "RisuRealm (URL trực tiếp)", | 1381 | "char_import_8": "RisuRealm (URL trực tiếp)", |
| 1382 | "char_import_9": "Soulkyn (URL trực tiếp)", | ||
| 1382 | "Supports importing multiple characters.": "Hỗ trợ nhập nhiều ký tự.", | 1383 | "Supports importing multiple characters.": "Hỗ trợ nhập nhiều ký tự.", |
| 1383 | "Write each URL or ID into a new line.": "Viết mỗi URL hoặc ID vào một dòng mới.", | 1384 | "Write each URL or ID into a new line.": "Viết mỗi URL hoặc ID vào một dòng mới.", |
| 1384 | "Export for character": "Xuất cho nhân vật", | 1385 | "Export for character": "Xuất cho nhân vật", |
| @@ -670,7 +670,7 @@ | |||
| 670 | "Square": "正方形", | 670 | "Square": "正方形", |
| 671 | "Rectangle": "矩形", | 671 | "Rectangle": "矩形", |
| 672 | "Chat Style:": "聊天风格:", | 672 | "Chat Style:": "聊天风格:", |
| 673 | "Flat": "扁平\n气泡\n文档", | 673 | "Flat": "扁平", |
| 674 | "Bubbles": "气泡", | 674 | "Bubbles": "气泡", |
| 675 | "Document": "文档", | 675 | "Document": "文档", |
| 676 | "Specify colors for your theme.": "指定您的主题的颜色。", | 676 | "Specify colors for your theme.": "指定您的主题的颜色。", |
| @@ -1893,6 +1893,7 @@ | |||
| 1893 | "char_import_6": "被允许的PNG直链(请参阅", | 1893 | "char_import_6": "被允许的PNG直链(请参阅", |
| 1894 | "char_import_7": ")", | 1894 | "char_import_7": ")", |
| 1895 | "char_import_8": "RisuRealm 角色(直链)", | 1895 | "char_import_8": "RisuRealm 角色(直链)", |
| 1896 | "char_import_9": "Soulkyn 角色(直链)", | ||
| 1896 | "Supports importing multiple characters.": "支持导入多个角色。", | 1897 | "Supports importing multiple characters.": "支持导入多个角色。", |
| 1897 | "Write each URL or ID into a new line.": "将每个 URL 或 ID 写入新行。", | 1898 | "Write each URL or ID into a new line.": "将每个 URL 或 ID 写入新行。", |
| 1898 | "Enter the Git URL of the extension to install": "输入扩展程序的 Git URL 以安装", | 1899 | "Enter the Git URL of the extension to install": "输入扩展程序的 Git URL 以安装", |
| @@ -19,7 +19,7 @@ | |||
| 19 | "Delete the preset": "刪除預設設定檔", | 19 | "Delete the preset": "刪除預設設定檔", |
| 20 | "novelaipresets": "NovelAI 預設設定檔", | 20 | "novelaipresets": "NovelAI 預設設定檔", |
| 21 | "Default": "預設", | 21 | "Default": "預設", |
| 22 | "openaipresets": "OpenAI 預設設定檔", | 22 | "openaipresets": "聊天補全預設設定檔", |
| 23 | "Text Completion presets": "文字補全預設設定檔", | 23 | "Text Completion presets": "文字補全預設設定檔", |
| 24 | "AI Module": "AI 模組", | 24 | "AI Module": "AI 模組", |
| 25 | "Changes the style of the generated text.": "變更生成文字的樣式。", | 25 | "Changes the style of the generated text.": "變更生成文字的樣式。", |
| @@ -506,9 +506,9 @@ | |||
| 506 | "Global Lore First": "全域知識書優先", | 506 | "Global Lore First": "全域知識書優先", |
| 507 | "Entries can activate other entries by mentioning their keywords": "條目可以透過提及其關鍵字來啟用其他條目", | 507 | "Entries can activate other entries by mentioning their keywords": "條目可以透過提及其關鍵字來啟用其他條目", |
| 508 | "Recursive Scan": "遞迴掃描", | 508 | "Recursive Scan": "遞迴掃描", |
| 509 | "Lookup for the entry keys in the context will respect the case": "在上下文中查詢條目鍵將區分大小寫", | 509 | "Lookup for the entry keys in the context will respect the case": "在上下文中查詢條目關鍵字將區分大小寫", |
| 510 | "Case Sensitive": "區分大小寫", | 510 | "Case Sensitive": "區分大小寫", |
| 511 | "If the entry key consists of only one word, it would not be matched as part of other words": "如果條目鍵僅包含一個詞,則不會作為其他詞的一部分進行配對", | 511 | "If the entry key consists of only one word, it would not be matched as part of other words": "如果條目關鍵字僅包含一個詞,則不會作為其他詞的一部分進行配對", |
| 512 | "Match Whole Words": "完全配對", | 512 | "Match Whole Words": "完全配對", |
| 513 | "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "只有符合最多鍵值數量的條目將被選中進行包含群組過濾", | 513 | "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "只有符合最多鍵值數量的條目將被選中進行包含群組過濾", |
| 514 | "Use Group Scoring": "使用群組評分", | 514 | "Use Group Scoring": "使用群組評分", |
| @@ -615,9 +615,9 @@ | |||
| 615 | "Compact Input Area (Mobile)": "緊湊的聊天訊息輸入欄(行動版)", | 615 | "Compact Input Area (Mobile)": "緊湊的聊天訊息輸入欄(行動版)", |
| 616 | "In the Character Management panel, show quick selection buttons for favorited characters": "在角色管理面板中,顯示加入到最愛角色的快速選擇按鈕。", | 616 | "In the Character Management panel, show quick selection buttons for favorited characters": "在角色管理面板中,顯示加入到最愛角色的快速選擇按鈕。", |
| 617 | "Characters Hotswap": "角色卡快捷選單", | 617 | "Characters Hotswap": "角色卡快捷選單", |
| 618 | "Enable magnification for zoomed avatar display.": "啟用放大顯示頭像", | 618 | "Enable magnification for zoomed avatar display.": "啟用放大功能檢視頭像。", |
| 619 | "Avatar Hover Magnification": "頭像懸停時的放大倍數", | 619 | "Avatar Hover Magnification": "頭像懸停時的放大倍數", |
| 620 | "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "當你在聊天中點選頭像的圖片後,這會啟用滑鼠懸停時的放大效果。", | 620 | "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "當您點選訊息中的角色頭像後,將啟用滑鼠懸停時的放大效果。", |
| 621 | "Show tagged character folders in the character list": "在角色列表中顯示標籤角色資料夾。", | 621 | "Show tagged character folders in the character list": "在角色列表中顯示標籤角色資料夾。", |
| 622 | "Tags as Folders": "標籤作為資料夾", | 622 | "Tags as Folders": "標籤作為資料夾", |
| 623 | "Tags_as_Folders_desc": "標籤必須在「標籤管理」選單中標記為資料夾才可適用。點選這裡開啟。", | 623 | "Tags_as_Folders_desc": "標籤必須在「標籤管理」選單中標記為資料夾才可適用。點選這裡開啟。", |
| @@ -769,7 +769,7 @@ | |||
| 769 | "Name": "名稱", | 769 | "Name": "名稱", |
| 770 | "Enter your name": "輸入您的名字", | 770 | "Enter your name": "輸入您的名字", |
| 771 | "Click to set a new User Name": "設定新的使用者名稱", | 771 | "Click to set a new User Name": "設定新的使用者名稱", |
| 772 | "Click to lock your selected persona to the current chat. Click again to remove the lock.": "鎖定目前所選的使用者角色至本次聊天。再次點選將移除鎖定。", | 772 | "Click to lock your selected persona to the current chat. Click again to remove the lock.": "綁定目前所選的使用者角色至本次聊天。再次點選將移除綁定。", |
| 773 | "Click to set user name for all messages": "設定所有訊息的使用者名稱", | 773 | "Click to set user name for all messages": "設定所有訊息的使用者名稱", |
| 774 | "Persona Description": "使用者角色描述", | 774 | "Persona Description": "使用者角色描述", |
| 775 | "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "範例:[{{user}} 是一個 28 歲的羅馬尼亞貓娘。]", | 775 | "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "範例:[{{user}} 是一個 28 歲的羅馬尼亞貓娘。]", |
| @@ -903,8 +903,8 @@ | |||
| 903 | "@ Depth": "@ 深度", | 903 | "@ Depth": "@ 深度", |
| 904 | "Role": "角色", | 904 | "Role": "角色", |
| 905 | "Talkativeness": "健談度", | 905 | "Talkativeness": "健談度", |
| 906 | "How often the character speaks in group chats!": "角色在群組聊天中說話的頻率!", | 906 | "How often the character speaks in group chats!": "角色在群組聊天中的發言頻率!", |
| 907 | "How often the character speaks in": "角色說話的頻率", | 907 | "How often the character speaks in": "角色發言頻率", |
| 908 | "group chats!": "群組聊天!", | 908 | "group chats!": "群組聊天!", |
| 909 | "Shy": "寡言", | 909 | "Shy": "寡言", |
| 910 | "Normal": "正常", | 910 | "Normal": "正常", |
| @@ -970,10 +970,10 @@ | |||
| 970 | "Comma separated list": "逗號分隔列表", | 970 | "Comma separated list": "逗號分隔列表", |
| 971 | "Switch to plaintext mode": "切換到純文字模式", | 971 | "Switch to plaintext mode": "切換到純文字模式", |
| 972 | "Logic": "邏輯", | 972 | "Logic": "邏輯", |
| 973 | "AND ANY": "AND 任何", | 973 | "AND ANY": "且「包含任一」", |
| 974 | "AND ALL": "AND 所有", | 974 | "AND ALL": "且「包含全部」", |
| 975 | "NOT ALL": "NOT 所有", | 975 | "NOT ALL": "且「未完全包含」", |
| 976 | "NOT ANY": "NOT 任何", | 976 | "NOT ANY": "且「完全不含」", |
| 977 | "(ignored if empty)": "(如果為空則忽略)", | 977 | "(ignored if empty)": "(如果為空則忽略)", |
| 978 | "Optional Filter": "選填過濾器", | 978 | "Optional Filter": "選填過濾器", |
| 979 | "Keywords or Regexes (ignored if empty)": "關鍵字或正規表示式(如果為空則忽略)", | 979 | "Keywords or Regexes (ignored if empty)": "關鍵字或正規表示式(如果為空則忽略)", |
| @@ -993,11 +993,11 @@ | |||
| 993 | "Filter to Character(s)": "角色篩選", | 993 | "Filter to Character(s)": "角色篩選", |
| 994 | "Character Exclusion": "角色排除", | 994 | "Character Exclusion": "角色排除", |
| 995 | "-- Characters not found --": "-- 未找到角色 --", | 995 | "-- Characters not found --": "-- 未找到角色 --", |
| 996 | "Inclusion Group": "包含的群組", | 996 | "Inclusion Group": "納入群組", |
| 997 | "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "如果觸發多個條目,包含群組可確保一次僅啟動一組中的一個條目。\r支援多個以逗號分隔的群組。\r\r文件:世界資訊——包容性集團", | 997 | "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "納入群組可確保在同一群組中,同時被觸發的多個條目僅有一個會被啟用。\r支援多個以逗號分隔的群組。\r詳見 SillyTavern 官方文件:World Info - Inclusion Group", |
| 998 | "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "優先考慮此條目:選取後,此條目將在所有選擇中優先。\r如果有多個優先順序,則選擇「順序」最高的一個。", | 998 | "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "優先此條目:勾選後,此條目將在所有可選條目中被優先考慮。\r若有多個條目同時設為優先,將選擇「順序(Order)」數值最高的條目。", |
| 999 | "Only one entry with the same label will be activated": "僅會啟用具有相同標籤的一個條目", | 999 | "Only one entry with the same label will be activated": "僅啟用一個具有相同標籤的條目", |
| 1000 | "A relative likelihood of entry activation within the group": "群組內條目啟用的相對可能性", | 1000 | "A relative likelihood of entry activation within the group": "此條目在群組中被選中的相對可能性", |
| 1001 | "Group Weight": "群組權重", | 1001 | "Group Weight": "群組權重", |
| 1002 | "Selective": "選擇性", | 1002 | "Selective": "選擇性", |
| 1003 | "Use Probability": "使用機率", | 1003 | "Use Probability": "使用機率", |
| @@ -1134,7 +1134,7 @@ | |||
| 1134 | "Manage chat files": "管理聊天檔案", | 1134 | "Manage chat files": "管理聊天檔案", |
| 1135 | "Delete messages": "刪除訊息", | 1135 | "Delete messages": "刪除訊息", |
| 1136 | "Regenerate": "重新生成", | 1136 | "Regenerate": "重新生成", |
| 1137 | "Ask AI to write your message for you": "請 AI 為您撰寫訊息", | 1137 | "Ask AI to write your message for you": "由 AI 扮演您的角色撰寫訊息", |
| 1138 | "Impersonate": "AI 扮演使用者", | 1138 | "Impersonate": "AI 扮演使用者", |
| 1139 | "Continue": "繼續", | 1139 | "Continue": "繼續", |
| 1140 | "Bind user name to that avatar": "將使用者名稱附加到該頭像", | 1140 | "Bind user name to that avatar": "將使用者名稱附加到該頭像", |
| @@ -1384,6 +1384,7 @@ | |||
| 1384 | "char_import_6": "直接 PNG 連結(請參閱", | 1384 | "char_import_6": "直接 PNG 連結(請參閱", |
| 1385 | "char_import_7": "對於允許的主機)", | 1385 | "char_import_7": "對於允許的主機)", |
| 1386 | "char_import_8": "RisuRealm 角色(直接連結)", | 1386 | "char_import_8": "RisuRealm 角色(直接連結)", |
| 1387 | "char_import_9": "Soulkyn 角色(直接連結)", | ||
| 1387 | "Supports importing multiple characters.": "支援匯入多個字元。", | 1388 | "Supports importing multiple characters.": "支援匯入多個字元。", |
| 1388 | "Write each URL or ID into a new line.": "將每個 URL 或 ID 寫入新行。", | 1389 | "Write each URL or ID into a new line.": "將每個 URL 或 ID 寫入新行。", |
| 1389 | "Export for character": "匯出字元", | 1390 | "Export for character": "匯出字元", |
| @@ -2382,7 +2383,7 @@ | |||
| 2382 | "Do you want to remove these fields before exporting?": "是否要在匯出前移除這些欄位?", | 2383 | "Do you want to remove these fields before exporting?": "是否要在匯出前移除這些欄位?", |
| 2383 | "Delete the preset? This action is irreversible and your current settings will be overwritten.": "確定刪除此預設設定檔?刪除後無法復原,且此設定將被覆蓋。", | 2384 | "Delete the preset? This action is irreversible and your current settings will be overwritten.": "確定刪除此預設設定檔?刪除後無法復原,且此設定將被覆蓋。", |
| 2384 | "Update all": "全部更新", | 2385 | "Update all": "全部更新", |
| 2385 | "Automatically chooses an alternative provider if chosen providers can't serve your request.": "當所選提供者無法滿足您的請求時,自動選擇替代提供者。", | 2386 | "Automatically chooses an alternative provider if chosen providers can't serve your request.": "當所選供應商無法滿足您的請求時,自動選擇替代供應商。", |
| 2386 | "Use extension settings": "使用擴充功能設定", | 2387 | "Use extension settings": "使用擴充功能設定", |
| 2387 | "To use instruct formatting, switch to OpenRouter under Text Completion API.": "若要使用指令格式,請在文字補全 API 下切換至 OpenRouter。", | 2388 | "To use instruct formatting, switch to OpenRouter under Text Completion API.": "若要使用指令格式,請在文字補全 API 下切換至 OpenRouter。", |
| 2388 | "Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.": "如果模型在達到一定數量的符元前停止,則自動繼續生成回應。", | 2389 | "Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.": "如果模型在達到一定數量的符元前停止,則自動繼續生成回應。", |
| @@ -2456,7 +2457,7 @@ | |||
| 2456 | "openai_reasoning_effort_low": "低", | 2457 | "openai_reasoning_effort_low": "低", |
| 2457 | "openai_reasoning_effort_medium": "中", | 2458 | "openai_reasoning_effort_medium": "中", |
| 2458 | "openai_reasoning_effort_high": "高", | 2459 | "openai_reasoning_effort_high": "高", |
| 2459 | "Reasoning": "推理 Reasoning", | 2460 | "Reasoning": "推理", |
| 2460 | "reasoning_auto_parse": "自動解析主要內容中推理區塊,需定義且不為空的前綴與後綴欄位。", | 2461 | "reasoning_auto_parse": "自動解析主要內容中推理區塊,需定義且不為空的前綴與後綴欄位。", |
| 2461 | "Auto-Parse": "自動解析", | 2462 | "Auto-Parse": "自動解析", |
| 2462 | "reasoning_auto_expand": "自動展開推理區塊。", | 2463 | "reasoning_auto_expand": "自動展開推理區塊。", |
| @@ -2556,7 +2557,7 @@ | |||
| 2556 | "Swiping a message will automatically trigger a re-summarization if it has already been summarized.": "滑動訊息後若已進行摘要,將自動觸發重新摘要。", | 2557 | "Swiping a message will automatically trigger a re-summarization if it has already been summarized.": "滑動訊息後若已進行摘要,將自動觸發重新摘要。", |
| 2557 | "Re-summarize on Swipe": "滑動後重新摘要", | 2558 | "Re-summarize on Swipe": "滑動後重新摘要", |
| 2558 | "Block chat input while summarizing.": "在摘要進行時暫時禁用聊天訊息輸入。", | 2559 | "Block chat input while summarizing.": "在摘要進行時暫時禁用聊天訊息輸入。", |
| 2559 | "Block Chat": "訊息輸入鎖定", | 2560 | "Block Chat": "鎖定訊息輸入", |
| 2560 | "Whether to use messages and/or summaries as context for summarization. You must use {{history}} in the summary prompt.": "決定是否在摘要中使用訊息及/或過往摘要作為背景資訊。需於摘要提示詞中,使用 {{history}}。", | 2561 | "Whether to use messages and/or summaries as context for summarization. You must use {{history}} in the summary prompt.": "決定是否在摘要中使用訊息及/或過往摘要作為背景資訊。需於摘要提示詞中,使用 {{history}}。", |
| 2561 | "Message History": "訊息歷史", | 2562 | "Message History": "訊息歷史", |
| 2562 | "Messages": "僅訊息", | 2563 | "Messages": "僅訊息", |
| @@ -2630,7 +2631,7 @@ | |||
| 2630 | "Allocates a portion of the response length for thinking (low: 10%, medium: 25%, high: 50%). Other options are model-dependent.": "分配部分回應長度用於推理功能(低:10%、中:25%、高:50%)。其他選項依模型而異。", | 2631 | "Allocates a portion of the response length for thinking (low: 10%, medium: 25%, high: 50%). Other options are model-dependent.": "分配部分回應長度用於推理功能(低:10%、中:25%、高:50%)。其他選項依模型而異。", |
| 2631 | "Attach a file or image to a current chat.": "附加檔案或圖片至目前的聊天。", | 2632 | "Attach a file or image to a current chat.": "附加檔案或圖片至目前的聊天。", |
| 2632 | "Change Persona Image": "變更使用者角色頭像", | 2633 | "Change Persona Image": "變更使用者角色頭像", |
| 2633 | "Click to lock your selected persona to the current character. Click again to remove the lock.": "點選以將所選使用者角色鎖定目前聊天的角色。再次點選以解除鎖定。", | 2634 | "Click to lock your selected persona to the current character. Click again to remove the lock.": "點選以將所選使用者角色與目前聊天的角色綁定。再次點選可解除綁定。", |
| 2634 | "Click to select this as default persona for the new chats. Click again to remove it.": "點選以將此設為新聊天的預設使用者角色,再次點選可取消設定。", | 2635 | "Click to select this as default persona for the new chats. Click again to remove it.": "點選以將此設為新聊天的預設使用者角色,再次點選可取消設定。", |
| 2635 | "Connected Personas": "已連結的使用者角色", | 2636 | "Connected Personas": "已連結的使用者角色", |
| 2636 | "Create a new prompt": "新增新提示詞", | 2637 | "Create a new prompt": "新增新提示詞", |
| @@ -2639,21 +2640,21 @@ | |||
| 2639 | "Duplicate Persona": "複製使用者角色", | 2640 | "Duplicate Persona": "複製使用者角色", |
| 2640 | "Expand and zoom": "展開並縮放", | 2641 | "Expand and zoom": "展開並縮放", |
| 2641 | "Move Entry to Another Lorebook": "將條目移動到其他知識書", | 2642 | "Move Entry to Another Lorebook": "將條目移動到其他知識書", |
| 2642 | "Persona is locked to the current character": "使用者角色已鎖定至目前角色", | 2643 | "Persona is locked to the current character": "使用者角色已綁定至目前角色", |
| 2643 | "Persona is locked to the current chat": "使用者角色已鎖定至目前聊天", | 2644 | "Persona is locked to the current chat": "使用者角色已綁定至目前聊天", |
| 2644 | "Rename a prompt": "重新命名提示詞", | 2645 | "Rename a prompt": "重新命名提示詞", |
| 2645 | "Rename Persona": "重新命名使用者角色", | 2646 | "Rename Persona": "重新命名使用者角色", |
| 2646 | "Select your current Reasoning Template": "選擇你目前使用的推理範本", | 2647 | "Select your current Reasoning Template": "選擇你目前使用的推理範本", |
| 2647 | "Toggles sprite scaling for character sprites.": "切換角色立繪的縮放比例", | 2648 | "Toggles sprite scaling for character sprites.": "切換角色立繪的縮放比例", |
| 2648 | "When multiple personas are connected to a character, a popup will appear to select which one to use.": "當多個使用者角色連接至一個角色時,將顯示選擇彈窗。", | 2649 | "When multiple personas are connected to a character, a popup will appear to select which one to use.": "當多個使用者角色連接至一個角色時,將顯示選擇彈窗。", |
| 2649 | "When using LLM or WebLLM classifier, only show and use expressions that have sprites assigned to them.": "使用 LLM 或 WebLLM 分類器時,僅顯示並使用已指派的表情立繪。", | 2650 | "When using LLM or WebLLM classifier, only show and use expressions that have sprites assigned to them.": "使用 LLM 或 WebLLM 分類器時,僅顯示並使用已指派的表情立繪。", |
| 2650 | "Whenever a persona is selected, it will be locked and automatically selected when the chat is opened.": "若已選擇使用者角色,將在開啟聊天時自動進行鎖定。", | 2651 | "Whenever a persona is selected, it will be locked and automatically selected when the chat is opened.": "若已選擇使用者角色,將在開啟聊天時自動進行綁定。", |
| 2651 | "Additional Matching Sources": "額外匹配來源", | 2652 | "Additional Matching Sources": "額外匹配來源", |
| 2652 | "All Classes": "所有類別", | 2653 | "All Classes": "所有類別", |
| 2653 | "Allow multiple persona connections per character": "允許每個角色連接多個使用者角色", | 2654 | "Allow multiple persona connections per character": "允許每個角色連接多個使用者角色", |
| 2654 | "Allows the model to return image attachments.": "允許模型返回圖片附件。", | 2655 | "Allows the model to return image attachments.": "允許模型返回圖片附件。", |
| 2655 | "Auto-Hide Sprite Settings": "自動隱藏立繪設定", | 2656 | "Auto-Hide Sprite Settings": "自動隱藏立繪設定", |
| 2656 | "Auto-lock a chosen persona to the chat": "自動鎖定使用者角色至聊天中", | 2657 | "Auto-lock a chosen persona to the chat": "自動綁定使用者角色至聊天中", |
| 2657 | "Character": "角色", | 2658 | "Character": "角色", |
| 2658 | "Character Personality": "角色個性", | 2659 | "Character Personality": "角色個性", |
| 2659 | "Character Tint/Share World Tint With Characters requires Prome to be enabled.": "角色著色/與角色共享世界著色功能需啟用 Prome。", | 2660 | "Character Tint/Share World Tint With Characters requires Prome to be enabled.": "角色著色/與角色共享世界著色功能需啟用 Prome。", |
| @@ -2703,7 +2704,7 @@ | |||
| 2703 | "Scan depth cannot be negative": "掃描深度不能為負值", | 2704 | "Scan depth cannot be negative": "掃描深度不能為負值", |
| 2704 | "Scan depth cannot exceed ${0}": "掃描深度不能超過 ${0}", | 2705 | "Scan depth cannot exceed ${0}": "掃描深度不能超過 ${0}", |
| 2705 | "Reasoning Template": "推理範本", | 2706 | "Reasoning Template": "推理範本", |
| 2706 | "OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level.": "OpenAI 支援程度:低、中、高。Minimum 與 Maximum 分別等同於低與高。選擇 Auto(自動)不會傳送努力等級。", | 2707 | "OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level.": "OpenAI 支援程度:低、中、高。Minimum 與 Maximum 分別等同於低與高。選擇 Auto(自動)不會傳送推理耗費等級。", |
| 2707 | "Branch or tag name (optional)": "分支/標籤名稱(可留空)", | 2708 | "Branch or tag name (optional)": "分支/標籤名稱(可留空)", |
| 2708 | "Update enabled": "僅更新啟用項目", | 2709 | "Update enabled": "僅更新啟用項目", |
| 2709 | "Sort: Loading Order": "排序:載入順序", | 2710 | "Sort: Loading Order": "排序:載入順序", |
| @@ -2742,5 +2743,126 @@ | |||
| 2742 | "You deleted a character/chat and arrived back here for safety reasons! Pick another character!": "角色或對話已被刪除。系統為安全考量導回此頁,請重新選擇角色。", | 2743 | "You deleted a character/chat and arrived back here for safety reasons! Pick another character!": "角色或對話已被刪除。系統為安全考量導回此頁,請重新選擇角色。", |
| 2743 | "Could not connect to API": "無法連線至 API", | 2744 | "Could not connect to API": "無法連線至 API", |
| 2744 | "Connected to API": "已成功連線至 API", | 2745 | "Connected to API": "已成功連線至 API", |
| 2745 | "help_macros_charDepthPrompt": "角色的 @ 深度註記" | 2746 | "help_macros_charDepthPrompt": "角色的 @ 深度註記", |
| 2747 | "Bind presets to API connections": "將預設綁定至 API 連線", | ||
| 2748 | "Allow compressing requests by removing messages from the middle of the prompt.": "允許透過移除提示中間的訊息來壓縮請求。", | ||
| 2749 | "Unknown": "未知", | ||
| 2750 | "Min Keep": "最小保留", | ||
| 2751 | "enable_functions_desc_4": "當使用「無工具」提示後處理時不支援!", | ||
| 2752 | "Send inline videos": "傳送內嵌影片", | ||
| 2753 | "video_inlining_hint_1": "若模型支援,則在提示中傳送影片。使用", | ||
| 2754 | "video_inlining_hint_2": "操作於任何訊息或使用", | ||
| 2755 | "video_inlining_hint_3": "選單以上傳影片檔案到聊天中。", | ||
| 2756 | "video_inlining_hint_4": "影片大小必須小於 20 MB 且長度低於 1 分鐘", | ||
| 2757 | "This setting affects visibility only.": "此設定僅影響可見性。", | ||
| 2758 | "Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking.": "為推理部分分配回應長度(最大回應長度至少需 1024 符元,低:10%、中:25%、高:50%、最高:95%)。選擇「自動」將不請求推理。", | ||
| 2759 | "Allocates a portion of the response length for thinking (Flash 2.5/Pro 2.5) (min: 0/128 tokens, low: 10%, medium: 25%, high: 50%, max: 24576/32768 tokens). Auto lets the model decide.": "為推理部分分配回應長度(Flash 2.5/Pro 2.5)(最少:0/128 符元,低:10%、中:25%、高:50%、最高:24576/32768 符元)。選擇「自動」將由模型決定。", | ||
| 2760 | "Save and connect": "儲存並連線", | ||
| 2761 | "Manage API keys": "管理 API 金鑰", | ||
| 2762 | "For privacy reasons, your API key will be hidden after you click 'Connect'.": "出於隱私考量,點選「連線」後,將隱藏您的 API 金鑰。", | ||
| 2763 | "Experimental feature. Use at your own risk.": "實驗性功能。請自行斟酌使用風險。", | ||
| 2764 | "suffix will be added automatically.": "後綴將自動新增。", | ||
| 2765 | "Google Vertex AI Configuration": "Google Vertex AI 設定", | ||
| 2766 | "Authentication Mode": "驗證模式:", | ||
| 2767 | "Express Mode (API Key)": "快速模式(API 金鑰)", | ||
| 2768 | "Full Version (Service Account)": "完整版(服務帳號)", | ||
| 2769 | "Google Vertex AI API Key": "Google Vertex AI API 金鑰", | ||
| 2770 | "(Express mode)": "(快速模式)", | ||
| 2771 | "Service Account Configuration": "服務帳號設定", | ||
| 2772 | "Region": "區域:", | ||
| 2773 | "View available regions and models": "檢視可用區域和模型", | ||
| 2774 | "Service Account JSON Content": "服務帳號 JSON 內容:", | ||
| 2775 | "For privacy reasons, your Service Account JSON content will be hidden after you click 'Validate JSON'.": "出於隱私考量,點選「驗證 JSON」將隱藏您的服務帳號 JSON 內容。", | ||
| 2776 | "Validate JSON": "驗證 JSON", | ||
| 2777 | "Pollinations Model": "Pollinations 模型", | ||
| 2778 | "Provided free of charge by Pollinations.AI": "由 Pollinations.AI 免費提供", | ||
| 2779 | "Avoid sending sensitive information. Provider's outputs may include ads.": "請避免傳送敏感資訊。供應商的輸出可能包含廣告。", | ||
| 2780 | "prompt_post_processing_merge_tools": "合併連續角色(含工具)", | ||
| 2781 | "prompt_post_processing_semi_tools": "半嚴格(角色交替;含工具)", | ||
| 2782 | "prompt_post_processing_strict_tools": "嚴格(使用者優先,角色交替;含工具)", | ||
| 2783 | "prompt_post_processing_single": "單一使用者訊息(無工具)", | ||
| 2784 | "Rounded": "圓角", | ||
| 2785 | "Notifications:": "系統通知:", | ||
| 2786 | "Top Left": "左上", | ||
| 2787 | "Top Center": "上方置中", | ||
| 2788 | "Top Right": "右上", | ||
| 2789 | "Bottom Left": "左下", | ||
| 2790 | "Bottom Center": "下方置中", | ||
| 2791 | "Bottom Right": "右下", | ||
| 2792 | "Click the message text in the chat log to edit it.": "點選對話訊息文字後即可編輯內容。", | ||
| 2793 | "Click to Edit": "點選以編輯聊天訊息", | ||
| 2794 | "Make animated backgrounds static in the selection menu. This will reduce UI and network lag if you have a large amount. This is only a change for the selection menu.": "將選單中的動畫背景靜態化,以減少背景過多所造成的介面與網路延遲。此設定僅影響選單。", | ||
| 2795 | "Animated background thumbnails": "動畫背景縮圖", | ||
| 2796 | "Find and delete backups, unused chats, files, images, etc.": "搜尋並刪除備份、未使用的聊天、檔案、圖片等。", | ||
| 2797 | "Clean-Up": "清理", | ||
| 2798 | "Always render style tags from greetings, even if the message is unloaded due to lazy loading.": "始終渲染問候訊息中的樣式標籤,即使該訊息因延遲載入而未顯示。", | ||
| 2799 | "Pin greeting message styles": "固定問候訊息樣式", | ||
| 2800 | "Visibility": "可見性", | ||
| 2801 | "Don't show": "不顯示", | ||
| 2802 | "Input length > 1": "輸入長度 > 1", | ||
| 2803 | "Always show": "始終顯示", | ||
| 2804 | "(DEPRECATED)": "(已淘汰)", | ||
| 2805 | "When multiple personas are connected to a character, a popup will appear to select which one to use": "當多個使用者角色綁定至同一角色時,將顯示選單以擇一。", | ||
| 2806 | "Whenever a persona is selected, it will be locked to the current chat and automatically selected when the chat is opened.": "您所選的使用者角色將綁定至目前聊天,並於開啟此聊天檔案時自動套用。", | ||
| 2807 | "Set / Unset as Welcome Page Assistant": "設定/取消為歡迎頁面助理", | ||
| 2808 | "Allow / Forbid the use of global styles for this character.": "允許/禁止此角色使用全域樣式。", | ||
| 2809 | "This character will be used as a welcome page assistant.": "此角色將用作歡迎頁面助理。", | ||
| 2810 | "prompt_manager_order": "順序", | ||
| 2811 | "prompt_manager_order_note": "來自其他來源(世界資訊、作者備註等)的提示注入預設順序為 100。", | ||
| 2812 | "Ordered from low/top to high/bottom, and at same order: Assistant, User, System.": "順序從低(上)至高(下);同順序時,排列為助理 > 使用者 > 系統。", | ||
| 2813 | "Source:": "來源:", | ||
| 2814 | "Secondary captioning endpoint URL": "次要說明文字端點 URL", | ||
| 2815 | "ext_regex_bulk_edit": "批次編輯", | ||
| 2816 | "Export": "匯出", | ||
| 2817 | "No scripts found": "未找到腳本", | ||
| 2818 | "ext_regex_flags_help": "點選此處了解更多關於正規表達式(regex)標誌的資訊。", | ||
| 2819 | "ext_regex_other_options_desc": "預設情況下,正規表達式腳本會直接且不可逆地變更聊天檔案。\r\n啟用以下任一(或兩者)選項將防止更改聊天檔案,同時仍會變更指定項目。", | ||
| 2820 | "This character has embedded regex script(s).": "此角色包含嵌入式正規表達式腳本。", | ||
| 2821 | "Would you like to allow using them?": "您想允許使用它們嗎?", | ||
| 2822 | "If you want to do it later, select \"Regex\" from the extensions menu.": "您可稍後從擴充功能選單中啟用 「正規表達式(Regex)」。", | ||
| 2823 | "SillyTavern Settings": "SillyTavern 設定", | ||
| 2824 | "Documentation": "文件", | ||
| 2825 | "Import from JSONL": "從 JSONL 匯入", | ||
| 2826 | "Load": "載入", | ||
| 2827 | "Export as JSONL": "匯出為 JSONL", | ||
| 2828 | "Delete all items in this category": "刪除此分類中的所有項目", | ||
| 2829 | "View item content": "檢視項目內容", | ||
| 2830 | "Download item": "下載項目", | ||
| 2831 | "Delete this item": "刪除此項目", | ||
| 2832 | "Once deleted, the files will be gone forever!": "一旦刪除,檔案將永久消失!", | ||
| 2833 | "Make sure to back up your data in advance.": "請先備份您的資料。", | ||
| 2834 | "Scan": "掃描", | ||
| 2835 | "No results yet. Tap 'Scan' to start scanning.": "尚無結果。點選「掃描」以開始掃描。", | ||
| 2836 | "Do you want to export connection data with the preset?": "您想將連線資料與預設一起匯出嗎?", | ||
| 2837 | "This includes the selected source, models, and other preferences set in the API Connections panel.": "這包括在 API 連線面板中設定的來源、模型及其他偏好設定。", | ||
| 2838 | "Your stored API keys are never exported.": "您的 API 金鑰將不會被匯出。", | ||
| 2839 | "Export connection data": "匯出連線資料", | ||
| 2840 | "Do not export connection data": "不匯出連線資料", | ||
| 2841 | "Creator's Notes contain CSS style tags. Do you want to apply them just to Creator's Notes or to the entire application?": "此創作者備註內含 CSS 樣式。請選擇是否僅套用於備註區域,或應用至整體介面。", | ||
| 2842 | "CAUTION: Malformed styles may cause issues.": "注意:樣式錯誤可能導致問題。", | ||
| 2843 | "To change the preference later, use the": "若想稍後更改偏好設定,請使用", | ||
| 2844 | "button in the Creator's Notes block.": "創作者備註區塊中的按鈕。", | ||
| 2845 | "Class names will be automatically prefixed with 'custom-'.": "CSS 類別名稱將自動套用「custom-」前綴。", | ||
| 2846 | "Choose how to apply CSS style tags if they are defined in Creator's Notes of this character:": "請選擇如何套用此角色創作者備註中的 CSS 樣式:", | ||
| 2847 | "Just to Creator's Notes": "僅限創作者備註", | ||
| 2848 | "Apply to the entire app": "應用於整個應用程式", | ||
| 2849 | "API:": "API:", | ||
| 2850 | "Key:": "金鑰:", | ||
| 2851 | "Add Secret": "新增密鑰", | ||
| 2852 | "No secrets saved.": "尚未儲存任何密鑰。", | ||
| 2853 | "Copy ID": "複製 ID", | ||
| 2854 | "Select": "選擇", | ||
| 2855 | "Show recent chats": "顯示最近的聊天", | ||
| 2856 | "Hide recent chats": "隱藏最近的聊天", | ||
| 2857 | "Recent Chats": "最近的聊天", | ||
| 2858 | "Docs": "文件", | ||
| 2859 | "GitHub": "GitHub", | ||
| 2860 | "Discord": "Discord", | ||
| 2861 | "Temporary Chat": "臨時聊天", | ||
| 2862 | "No recent chats": "沒有最近的聊天", | ||
| 2863 | "(Message Box)": "(訊息框)", | ||
| 2864 | "[title]Create a new": "新增", | ||
| 2865 | "[title]Delete a ": "刪除 ", | ||
| 2866 | "[title]Rename a ": "重新命名 ", | ||
| 2867 | "completions note prefix": "完成提示前綴" | ||
| 2746 | } | 2868 | } |
| @@ -10,7 +10,6 @@ import { | |||
| 10 | SVGInject, | 10 | SVGInject, |
| 11 | Popper, | 11 | Popper, |
| 12 | initLibraryShims, | 12 | initLibraryShims, |
| 13 | slideToggle, | ||
| 14 | default as libs, | 13 | default as libs, |
| 15 | } from './lib.js'; | 14 | } from './lib.js'; |
| 16 | 15 | ||
| @@ -209,6 +208,7 @@ import { | |||
| 209 | } from './scripts/tags.js'; | 208 | } from './scripts/tags.js'; |
| 210 | import { | 209 | import { |
| 211 | SECRET_KEYS, | 210 | SECRET_KEYS, |
| 211 | initSecrets, | ||
| 212 | readSecretState, | 212 | readSecretState, |
| 213 | secret_state, | 213 | secret_state, |
| 214 | writeSecret, | 214 | writeSecret, |
| @@ -250,7 +250,20 @@ import { | |||
| 250 | import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js'; | 250 | import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js'; |
| 251 | import { hideLoader, showLoader } from './scripts/loader.js'; | 251 | import { hideLoader, showLoader } from './scripts/loader.js'; |
| 252 | import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js'; | 252 | import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js'; |
| 253 | import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels, loadGenericModels } from './scripts/textgen-models.js'; | 253 | import { |
| 254 | loadFeatherlessModels, | ||
| 255 | loadMancerModels, | ||
| 256 | loadOllamaModels, | ||
| 257 | loadTogetherAIModels, | ||
| 258 | loadInfermaticAIModels, | ||
| 259 | loadOpenRouterModels, | ||
| 260 | loadVllmModels, | ||
| 261 | loadAphroditeModels, | ||
| 262 | loadDreamGenModels, | ||
| 263 | initTextGenModels, | ||
| 264 | loadTabbyModels, | ||
| 265 | loadGenericModels, | ||
| 266 | } from './scripts/textgen-models.js'; | ||
| 254 | import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat, formatCreatorNotes, initChatUtilities } from './scripts/chats.js'; | 267 | import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat, formatCreatorNotes, initChatUtilities } from './scripts/chats.js'; |
| 255 | import { getPresetManager, initPresetManager } from './scripts/preset-manager.js'; | 268 | import { getPresetManager, initPresetManager } from './scripts/preset-manager.js'; |
| 256 | import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js'; | 269 | import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js'; |
| @@ -283,6 +296,7 @@ import { getContext } from './scripts/st-context.js'; | |||
| 283 | import { extractReasoningFromData, initReasoning, parseReasoningInSwipes, PromptReasoning, ReasoningHandler, removeReasoningFromString, updateReasoningUI } from './scripts/reasoning.js'; | 296 | import { extractReasoningFromData, initReasoning, parseReasoningInSwipes, PromptReasoning, ReasoningHandler, removeReasoningFromString, updateReasoningUI } from './scripts/reasoning.js'; |
| 284 | import { accountStorage } from './scripts/util/AccountStorage.js'; | 297 | import { accountStorage } from './scripts/util/AccountStorage.js'; |
| 285 | import { initWelcomeScreen, openPermanentAssistantChat, openPermanentAssistantCard, getPermanentAssistantAvatar } from './scripts/welcome-screen.js'; | 298 | import { initWelcomeScreen, openPermanentAssistantChat, openPermanentAssistantCard, getPermanentAssistantAvatar } from './scripts/welcome-screen.js'; |
| 299 | import { initDataMaid } from './scripts/data-maid.js'; | ||
| 286 | 300 | ||
| 287 | // API OBJECT FOR EXTERNAL WIRING | 301 | // API OBJECT FOR EXTERNAL WIRING |
| 288 | globalThis.SillyTavern = { | 302 | globalThis.SillyTavern = { |
| @@ -482,6 +496,7 @@ export const event_types = { | |||
| 482 | GENERATION_STARTED: 'generation_started', | 496 | GENERATION_STARTED: 'generation_started', |
| 483 | GENERATION_STOPPED: 'generation_stopped', | 497 | GENERATION_STOPPED: 'generation_stopped', |
| 484 | GENERATION_ENDED: 'generation_ended', | 498 | GENERATION_ENDED: 'generation_ended', |
| 499 | SD_PROMPT_PROCESSING: 'sd_prompt_processing', | ||
| 485 | EXTENSIONS_FIRST_LOAD: 'extensions_first_load', | 500 | EXTENSIONS_FIRST_LOAD: 'extensions_first_load', |
| 486 | EXTENSION_SETTINGS_LOADED: 'extension_settings_loaded', | 501 | EXTENSION_SETTINGS_LOADED: 'extension_settings_loaded', |
| 487 | SETTINGS_LOADED: 'settings_loaded', | 502 | SETTINGS_LOADED: 'settings_loaded', |
| @@ -541,6 +556,10 @@ export const event_types = { | |||
| 541 | TOOL_CALLS_PERFORMED: 'tool_calls_performed', | 556 | TOOL_CALLS_PERFORMED: 'tool_calls_performed', |
| 542 | TOOL_CALLS_RENDERED: 'tool_calls_rendered', | 557 | TOOL_CALLS_RENDERED: 'tool_calls_rendered', |
| 543 | CHARACTER_MANAGEMENT_DROPDOWN: 'charManagementDropdown', | 558 | CHARACTER_MANAGEMENT_DROPDOWN: 'charManagementDropdown', |
| 559 | SECRET_WRITTEN: 'secret_written', | ||
| 560 | SECRET_DELETED: 'secret_deleted', | ||
| 561 | SECRET_ROTATED: 'secret_rotated', | ||
| 562 | SECRET_EDITED: 'secret_edited', | ||
| 544 | }; | 563 | }; |
| 545 | 564 | ||
| 546 | export const eventSource = new EventEmitter([event_types.APP_READY]); | 565 | export const eventSource = new EventEmitter([event_types.APP_READY]); |
| @@ -672,16 +691,8 @@ export const extension_prompt_roles = { | |||
| 672 | 691 | ||
| 673 | export const MAX_INJECTION_DEPTH = 10000; | 692 | export const MAX_INJECTION_DEPTH = 10000; |
| 674 | 693 | ||
| 675 | const SAFETY_CHAT = [ | 694 | // Initialized in getSystemMessages() |
| 676 | { | 695 | const SAFETY_CHAT = []; |
| 677 | name: systemUserName, | ||
| 678 | force_avatar: system_avatar, | ||
| 679 | is_system: true, | ||
| 680 | is_user: false, | ||
| 681 | create_date: 0, | ||
| 682 | mes: 'You deleted a character/chat and arrived back here for safety reasons! Pick another character!', | ||
| 683 | }, | ||
| 684 | ]; | ||
| 685 | 696 | ||
| 686 | export let system_messages = {}; | 697 | export let system_messages = {}; |
| 687 | 698 | ||
| @@ -768,22 +779,17 @@ async function getSystemMessages() { | |||
| 768 | }, | 779 | }, |
| 769 | }, | 780 | }, |
| 770 | }; | 781 | }; |
| 771 | } | ||
| 772 | |||
| 773 | // Register configuration migrations | ||
| 774 | registerPromptManagerMigration(); | ||
| 775 | 782 | ||
| 776 | $(document).ajaxError(function myErrorHandler(_, xhr) { | 783 | const safetyMessage = { |
| 777 | // Cohee: CSRF doesn't error out in multiple tabs anymore, so this is unnecessary | 784 | name: systemUserName, |
| 778 | /* | 785 | force_avatar: system_avatar, |
| 779 | if (xhr.status == 403) { | 786 | is_system: true, |
| 780 | toastr.warning( | 787 | is_user: false, |
| 781 | 'doubleCsrf errors in console are NORMAL in this case. If you want to run ST in multiple tabs, start the server with --disableCsrf option.', | 788 | create_date: 0, |
| 782 | 'Looks like you\'ve opened SillyTavern in another browser tab', | 789 | mes: t`You deleted a character/chat and arrived back here for safety reasons! Pick another character!`, |
| 783 | { timeOut: 0, extendedTimeOut: 0, preventDuplicates: true }, | 790 | }; |
| 784 | ); | 791 | SAFETY_CHAT.splice(0, SAFETY_CHAT.length, safetyMessage); |
| 785 | } */ | 792 | } |
| 786 | }); | ||
| 787 | 793 | ||
| 788 | async function getClientVersion() { | 794 | async function getClientVersion() { |
| 789 | try { | 795 | try { |
| @@ -865,7 +871,8 @@ export let create_save = { | |||
| 865 | creator: '', | 871 | creator: '', |
| 866 | personality: '', | 872 | personality: '', |
| 867 | first_message: '', | 873 | first_message: '', |
| 868 | avatar: '', | 874 | /** @type {FileList|null} */ |
| 875 | avatar: null, | ||
| 869 | scenario: '', | 876 | scenario: '', |
| 870 | mes_example: '', | 877 | mes_example: '', |
| 871 | world: '', | 878 | world: '', |
| @@ -982,11 +989,14 @@ async function firstLoadInit() { | |||
| 982 | } | 989 | } |
| 983 | 990 | ||
| 984 | showLoader(); | 991 | showLoader(); |
| 992 | registerPromptManagerMigration(); | ||
| 993 | initStandaloneMode(); | ||
| 985 | initLibraryShims(); | 994 | initLibraryShims(); |
| 986 | addShowdownPatch(showdown); | 995 | addShowdownPatch(showdown); |
| 987 | reloadMarkdownProcessor(); | 996 | reloadMarkdownProcessor(); |
| 988 | applyBrowserFixes(); | 997 | applyBrowserFixes(); |
| 989 | await getClientVersion(); | 998 | await getClientVersion(); |
| 999 | await initSecrets(); | ||
| 990 | await readSecretState(); | 1000 | await readSecretState(); |
| 991 | await initLocales(); | 1001 | await initLocales(); |
| 992 | initChatUtilities(); | 1002 | initChatUtilities(); |
| @@ -1026,6 +1036,7 @@ async function firstLoadInit() { | |||
| 1026 | initWelcomeScreen(); | 1036 | initWelcomeScreen(); |
| 1027 | await initScrapers(); | 1037 | await initScrapers(); |
| 1028 | initCustomSelectedSamplers(); | 1038 | initCustomSelectedSamplers(); |
| 1039 | initDataMaid(); | ||
| 1029 | addDebugFunctions(); | 1040 | addDebugFunctions(); |
| 1030 | doDailyExtensionUpdatesCheck(); | 1041 | doDailyExtensionUpdatesCheck(); |
| 1031 | await hideLoader(); | 1042 | await hideLoader(); |
| @@ -1039,6 +1050,13 @@ async function fixViewport() { | |||
| 1039 | document.body.style.position = ''; | 1050 | document.body.style.position = ''; |
| 1040 | } | 1051 | } |
| 1041 | 1052 | ||
| 1053 | function initStandaloneMode() { | ||
| 1054 | const isPwaMode = window.matchMedia('(display-mode: standalone)').matches; | ||
| 1055 | if (isPwaMode) { | ||
| 1056 | $('body').addClass('PWA'); | ||
| 1057 | } | ||
| 1058 | } | ||
| 1059 | |||
| 1042 | function cancelStatusCheck(reason = 'Manually cancelled status check') { | 1060 | function cancelStatusCheck(reason = 'Manually cancelled status check') { |
| 1043 | abortStatusCheck?.abort(new AbortReason(reason)); | 1061 | abortStatusCheck?.abort(new AbortReason(reason)); |
| 1044 | abortStatusCheck = new AbortController(); | 1062 | abortStatusCheck = new AbortController(); |
| @@ -1395,7 +1413,6 @@ export function resultCheckStatus() { | |||
| 1395 | stopStatusLoading(); | 1413 | stopStatusLoading(); |
| 1396 | } | 1414 | } |
| 1397 | 1415 | ||
| 1398 | |||
| 1399 | /** | 1416 | /** |
| 1400 | * Switches the currently selected character to the one with the given ID. (character index, not the character key!) | 1417 | * Switches the currently selected character to the one with the given ID. (character index, not the character key!) |
| 1401 | * | 1418 | * |
| @@ -1880,6 +1897,52 @@ async function delChat(chatfile) { | |||
| 1880 | } | 1897 | } |
| 1881 | } | 1898 | } |
| 1882 | 1899 | ||
| 1900 | /** | ||
| 1901 | * Deletes a character chat by its name. | ||
| 1902 | * @param {string} characterId Character ID to delete chat for | ||
| 1903 | * @param {string} fileName Name of the chat file to delete (without .jsonl extension) | ||
| 1904 | * @returns {Promise<void>} A promise that resolves when the chat is deleted. | ||
| 1905 | */ | ||
| 1906 | export async function deleteCharacterChatByName(characterId, fileName) { | ||
| 1907 | // Make sure all the data is loaded. | ||
| 1908 | await unshallowCharacter(characterId); | ||
| 1909 | |||
| 1910 | /** @type {import('./scripts/char-data.js').v1CharData} */ | ||
| 1911 | const character = characters[characterId]; | ||
| 1912 | if (!character) { | ||
| 1913 | console.warn(`Character with ID ${characterId} not found.`); | ||
| 1914 | return; | ||
| 1915 | } | ||
| 1916 | |||
| 1917 | const response = await fetch('/api/chats/delete', { | ||
| 1918 | method: 'POST', | ||
| 1919 | headers: getRequestHeaders(), | ||
| 1920 | body: JSON.stringify({ | ||
| 1921 | chatfile: `${fileName}.jsonl`, | ||
| 1922 | avatar_url: character.avatar, | ||
| 1923 | }), | ||
| 1924 | }); | ||
| 1925 | |||
| 1926 | if (!response.ok) { | ||
| 1927 | console.error('Failed to delete chat for character.'); | ||
| 1928 | return; | ||
| 1929 | } | ||
| 1930 | |||
| 1931 | if (fileName === character.chat) { | ||
| 1932 | const chatsResponse = await fetch('/api/characters/chats', { | ||
| 1933 | method: 'POST', | ||
| 1934 | headers: getRequestHeaders(), | ||
| 1935 | body: JSON.stringify({ avatar_url: character.avatar }), | ||
| 1936 | }); | ||
| 1937 | const chats = Object.values(await chatsResponse.json()); | ||
| 1938 | chats.sort((a, b) => sortMoments(timestampToMoment(a.last_mes), timestampToMoment(b.last_mes))); | ||
| 1939 | const newChatName = chats.length && typeof chats[0] === 'object' ? chats[0].file_name.replace('.jsonl', '') : `${character.name} - ${humanizedDateTime()}`; | ||
| 1940 | await updateRemoteChatName(characterId, newChatName); | ||
| 1941 | } | ||
| 1942 | |||
| 1943 | await eventSource.emit(event_types.CHAT_DELETED, fileName); | ||
| 1944 | } | ||
| 1945 | |||
| 1883 | export async function replaceCurrentChat() { | 1946 | export async function replaceCurrentChat() { |
| 1884 | await clearChat(); | 1947 | await clearChat(); |
| 1885 | chat.length = 0; | 1948 | chat.length = 0; |
| @@ -2391,7 +2454,7 @@ export function appendMediaToMessage(mes, messageElement, adjustScroll = true) { | |||
| 2391 | const image = messageElement.find('.mes_img'); | 2454 | const image = messageElement.find('.mes_img'); |
| 2392 | const text = messageElement.find('.mes_text'); | 2455 | const text = messageElement.find('.mes_text'); |
| 2393 | const isInline = !!mes.extra?.inline_image; | 2456 | const isInline = !!mes.extra?.inline_image; |
| 2394 | image.off('load').on('load', function () { | 2457 | const doAdjustScroll = () => { |
| 2395 | if (!adjustScroll) { | 2458 | if (!adjustScroll) { |
| 2396 | return; | 2459 | return; |
| 2397 | } | 2460 | } |
| @@ -2399,6 +2462,16 @@ export function appendMediaToMessage(mes, messageElement, adjustScroll = true) { | |||
| 2399 | const newChatHeight = $('#chat').prop('scrollHeight'); | 2462 | const newChatHeight = $('#chat').prop('scrollHeight'); |
| 2400 | const diff = newChatHeight - chatHeight; | 2463 | const diff = newChatHeight - chatHeight; |
| 2401 | $('#chat').scrollTop(scrollPosition + diff); | 2464 | $('#chat').scrollTop(scrollPosition + diff); |
| 2465 | }; | ||
| 2466 | image.off('load').on('load', function () { | ||
| 2467 | image.removeAttr('alt'); | ||
| 2468 | image.removeClass('error'); | ||
| 2469 | doAdjustScroll(); | ||
| 2470 | }); | ||
| 2471 | image.off('error').on('error', function () { | ||
| 2472 | image.attr('alt', ''); | ||
| 2473 | image.addClass('error'); | ||
| 2474 | doAdjustScroll(); | ||
| 2402 | }); | 2475 | }); |
| 2403 | image.attr('src', mes.extra?.image); | 2476 | image.attr('src', mes.extra?.image); |
| 2404 | image.attr('title', mes.extra?.title || mes.title || ''); | 2477 | image.attr('title', mes.extra?.title || mes.title || ''); |
| @@ -2425,6 +2498,31 @@ export function appendMediaToMessage(mes, messageElement, adjustScroll = true) { | |||
| 2425 | } | 2498 | } |
| 2426 | } | 2499 | } |
| 2427 | 2500 | ||
| 2501 | // Add video to message | ||
| 2502 | if (mes.extra?.video) { | ||
| 2503 | const container = messageElement.find('.mes_block'); | ||
| 2504 | const chatHeight = $('#chat').prop('scrollHeight'); | ||
| 2505 | |||
| 2506 | // Create video element if it doesn't exist | ||
| 2507 | let video = messageElement.find('.mes_video'); | ||
| 2508 | if (video.length === 0) { | ||
| 2509 | video = $('<video class="mes_video" controls preload="metadata"></video>'); | ||
| 2510 | container.append(video); | ||
| 2511 | } | ||
| 2512 | |||
| 2513 | video.off('loadedmetadata').on('loadedmetadata', function () { | ||
| 2514 | if (!adjustScroll) { | ||
| 2515 | return; | ||
| 2516 | } | ||
| 2517 | const scrollPosition = $('#chat').scrollTop(); | ||
| 2518 | const newChatHeight = $('#chat').prop('scrollHeight'); | ||
| 2519 | const diff = newChatHeight - chatHeight; | ||
| 2520 | $('#chat').scrollTop(scrollPosition + diff); | ||
| 2521 | }); | ||
| 2522 | |||
| 2523 | video.attr('src', mes.extra?.video); | ||
| 2524 | } | ||
| 2525 | |||
| 2428 | // Add file to message | 2526 | // Add file to message |
| 2429 | if (mes.extra?.file) { | 2527 | if (mes.extra?.file) { |
| 2430 | messageElement.find('.mes_file_container').remove(); | 2528 | messageElement.find('.mes_file_container').remove(); |
| @@ -2646,7 +2744,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll | |||
| 2646 | 2744 | ||
| 2647 | /** | 2745 | /** |
| 2648 | * Returns the URL of the avatar for the given character Id. | 2746 | * Returns the URL of the avatar for the given character Id. |
| 2649 | * @param {number} characterId Character Id | 2747 | * @param {number|string} characterId Character Id |
| 2650 | * @returns {string} Avatar URL | 2748 | * @returns {string} Avatar URL |
| 2651 | */ | 2749 | */ |
| 2652 | export function getCharacterAvatar(characterId) { | 2750 | export function getCharacterAvatar(characterId) { |
| @@ -3520,7 +3618,7 @@ class StreamingProcessor { | |||
| 3520 | } | 3618 | } |
| 3521 | 3619 | ||
| 3522 | if (this.image) { | 3620 | if (this.image) { |
| 3523 | await processImageAttachment(chat[messageId], { imageUrl: this.image, parsedImage: null }); | 3621 | await processImageAttachment(chat[messageId], { imageUrl: this.image }); |
| 3524 | appendMediaToMessage(chat[messageId], $(this.messageDom)); | 3622 | appendMediaToMessage(chat[messageId], $(this.messageDom)); |
| 3525 | } | 3623 | } |
| 3526 | 3624 | ||
| @@ -3678,6 +3776,7 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | |||
| 3678 | if (responseLengthCustomized) { | 3776 | if (responseLengthCustomized) { |
| 3679 | TempResponseLength.save(api, responseLength); | 3777 | TempResponseLength.save(api, responseLength); |
| 3680 | } | 3778 | } |
| 3779 | /** @type {object|any[]} */ | ||
| 3681 | let generateData = {}; | 3780 | let generateData = {}; |
| 3682 | 3781 | ||
| 3683 | switch (api) { | 3782 | switch (api) { |
| @@ -6027,7 +6126,11 @@ export function extractMessageFromData(data, activeApi = null) { | |||
| 6027 | case 'koboldhorde': | 6126 | case 'koboldhorde': |
| 6028 | return data.text; | 6127 | return data.text; |
| 6029 | case 'textgenerationwebui': | 6128 | case 'textgenerationwebui': |
| 6030 | return data.choices?.[0]?.text ?? data.content ?? data.response ?? ''; | 6129 | return data.choices?.[0]?.text |
| 6130 | ?? data.choices?.[0]?.message?.content | ||
| 6131 | ?? data.content | ||
| 6132 | ?? data.response | ||
| 6133 | ?? ''; | ||
| 6031 | case 'novel': | 6134 | case 'novel': |
| 6032 | return data.output; | 6135 | return data.output; |
| 6033 | case 'openai': | 6136 | case 'openai': |
| @@ -6263,17 +6366,11 @@ export function cleanUpMessage({ getMessage, isImpersonate, isContinue, displayI | |||
| 6263 | * Adds an image to the message. | 6366 | * Adds an image to the message. |
| 6264 | * @param {object} message Message object | 6367 | * @param {object} message Message object |
| 6265 | * @param {object} sources Image sources | 6368 | * @param {object} sources Image sources |
| 6266 | * @param {ParsedImage} [sources.parsedImage] Parsed image | ||
| 6267 | * @param {string} [sources.imageUrl] Image URL | 6369 | * @param {string} [sources.imageUrl] Image URL |
| 6268 | * | 6370 | * |
| 6269 | * @returns {Promise<void>} | 6371 | * @returns {Promise<void>} |
| 6270 | */ | 6372 | */ |
| 6271 | async function processImageAttachment(message, { parsedImage, imageUrl }) { | 6373 | async function processImageAttachment(message, { imageUrl }) { |
| 6272 | if (parsedImage?.image) { | ||
| 6273 | saveImageToMessage(parsedImage, message); | ||
| 6274 | return; | ||
| 6275 | } | ||
| 6276 | |||
| 6277 | if (!imageUrl) { | 6374 | if (!imageUrl) { |
| 6278 | return; | 6375 | return; |
| 6279 | } | 6376 | } |
| @@ -6332,8 +6429,6 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | |||
| 6332 | 6429 | ||
| 6333 | let oldMessage = ''; | 6430 | let oldMessage = ''; |
| 6334 | const generationFinished = new Date(); | 6431 | const generationFinished = new Date(); |
| 6335 | const parsedImage = extractImageFromMessage(getMessage); | ||
| 6336 | getMessage = parsedImage.getMessage; | ||
| 6337 | if (type === 'swipe') { | 6432 | if (type === 'swipe') { |
| 6338 | oldMessage = chat[chat.length - 1]['mes']; | 6433 | oldMessage = chat[chat.length - 1]['mes']; |
| 6339 | chat[chat.length - 1]['swipes'].length++; | 6434 | chat[chat.length - 1]['swipes'].length++; |
| @@ -6347,7 +6442,7 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | |||
| 6347 | chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); | 6442 | chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); |
| 6348 | chat[chat.length - 1]['extra']['reasoning'] = reasoning; | 6443 | chat[chat.length - 1]['extra']['reasoning'] = reasoning; |
| 6349 | chat[chat.length - 1]['extra']['reasoning_duration'] = null; | 6444 | chat[chat.length - 1]['extra']['reasoning_duration'] = null; |
| 6350 | await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl }); | 6445 | await processImageAttachment(chat[chat.length - 1], { imageUrl }); |
| 6351 | if (power_user.message_token_count_enabled) { | 6446 | if (power_user.message_token_count_enabled) { |
| 6352 | const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; | 6447 | const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; |
| 6353 | chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); | 6448 | chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); |
| @@ -6371,7 +6466,7 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | |||
| 6371 | chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); | 6466 | chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); |
| 6372 | chat[chat.length - 1]['extra']['reasoning'] = reasoning; | 6467 | chat[chat.length - 1]['extra']['reasoning'] = reasoning; |
| 6373 | chat[chat.length - 1]['extra']['reasoning_duration'] = null; | 6468 | chat[chat.length - 1]['extra']['reasoning_duration'] = null; |
| 6374 | await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl }); | 6469 | await processImageAttachment(chat[chat.length - 1], { imageUrl }); |
| 6375 | if (power_user.message_token_count_enabled) { | 6470 | if (power_user.message_token_count_enabled) { |
| 6376 | const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; | 6471 | const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; |
| 6377 | chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); | 6472 | chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); |
| @@ -6391,7 +6486,7 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | |||
| 6391 | chat[chat.length - 1]['extra']['api'] = getGeneratingApi(); | 6486 | chat[chat.length - 1]['extra']['api'] = getGeneratingApi(); |
| 6392 | chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); | 6487 | chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); |
| 6393 | chat[chat.length - 1]['extra']['reasoning'] += reasoning; | 6488 | chat[chat.length - 1]['extra']['reasoning'] += reasoning; |
| 6394 | await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl }); | 6489 | await processImageAttachment(chat[chat.length - 1], { imageUrl }); |
| 6395 | // We don't know if the reasoning duration extended, so we don't update it here on purpose. | 6490 | // We don't know if the reasoning duration extended, so we don't update it here on purpose. |
| 6396 | if (power_user.message_token_count_enabled) { | 6491 | if (power_user.message_token_count_enabled) { |
| 6397 | const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; | 6492 | const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; |
| @@ -6437,7 +6532,7 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | |||
| 6437 | chat[chat.length - 1]['extra']['gen_id'] = group_generation_id; | 6532 | chat[chat.length - 1]['extra']['gen_id'] = group_generation_id; |
| 6438 | } | 6533 | } |
| 6439 | 6534 | ||
| 6440 | await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl: imageUrl }); | 6535 | await processImageAttachment(chat[chat.length - 1], { imageUrl }); |
| 6441 | const chat_id = (chat.length - 1); | 6536 | const chat_id = (chat.length - 1); |
| 6442 | 6537 | ||
| 6443 | !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); | 6538 | !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); |
| @@ -6654,15 +6749,6 @@ function getGeneratingModel(mes) { | |||
| 6654 | return model; | 6749 | return model; |
| 6655 | } | 6750 | } |
| 6656 | 6751 | ||
| 6657 | function extractImageFromMessage(getMessage) { | ||
| 6658 | const regex = /<img src="(.*?)".*?alt="(.*?)".*?>/g; | ||
| 6659 | const results = regex.exec(getMessage); | ||
| 6660 | const image = results ? results[1] : ''; | ||
| 6661 | const title = results ? results[2] : ''; | ||
| 6662 | getMessage = getMessage.replace(regex, ''); | ||
| 6663 | return { getMessage, image, title, inline: true }; | ||
| 6664 | } | ||
| 6665 | |||
| 6666 | /** | 6752 | /** |
| 6667 | * A function mainly used to switch 'generating' state - setting it to false and activating the buttons again | 6753 | * A function mainly used to switch 'generating' state - setting it to false and activating the buttons again |
| 6668 | */ | 6754 | */ |
| @@ -7073,6 +7159,11 @@ export async function saveChat({ chatName, withMetadata, mesId, force = false } | |||
| 7073 | } | 7159 | } |
| 7074 | } | 7160 | } |
| 7075 | 7161 | ||
| 7162 | /** | ||
| 7163 | * Processes the avatar image from the input element, allowing the user to crop it if necessary. | ||
| 7164 | * @param {HTMLInputElement} input - The input element containing the avatar file. | ||
| 7165 | * @returns {Promise<void>} | ||
| 7166 | */ | ||
| 7076 | async function read_avatar_load(input) { | 7167 | async function read_avatar_load(input) { |
| 7077 | if (input.files && input.files[0]) { | 7168 | if (input.files && input.files[0]) { |
| 7078 | if (selected_button == 'create') { | 7169 | if (selected_button == 'create') { |
| @@ -7104,7 +7195,7 @@ async function read_avatar_load(input) { | |||
| 7104 | await createOrEditCharacter(); | 7195 | await createOrEditCharacter(); |
| 7105 | await delay(DEFAULT_SAVE_EDIT_TIMEOUT); | 7196 | await delay(DEFAULT_SAVE_EDIT_TIMEOUT); |
| 7106 | 7197 | ||
| 7107 | const formData = new FormData($('#form_create').get(0)); | 7198 | const formData = new FormData(/** @type {HTMLFormElement} */($('#form_create').get(0))); |
| 7108 | await fetch(getThumbnailUrl('avatar', formData.get('avatar_url')), { | 7199 | await fetch(getThumbnailUrl('avatar', formData.get('avatar_url')), { |
| 7109 | method: 'GET', | 7200 | method: 'GET', |
| 7110 | cache: 'no-cache', | 7201 | cache: 'no-cache', |
| @@ -7114,22 +7205,21 @@ async function read_avatar_load(input) { | |||
| 7114 | }, | 7205 | }, |
| 7115 | }); | 7206 | }); |
| 7116 | 7207 | ||
| 7117 | $('.mes').each(async function () { | 7208 | const messages = $('.mes').toArray(); |
| 7118 | const nameMatch = $(this).attr('ch_name') == formData.get('ch_name'); | 7209 | for (const el of messages) { |
| 7119 | if ($(this).attr('is_system') == 'true' && !nameMatch) { | 7210 | const $el = $(el); |
| 7120 | return; | 7211 | const nameMatch = $el.attr('ch_name') == formData.get('ch_name'); |
| 7121 | } | 7212 | if ($el.attr('is_system') == 'true' && !nameMatch) continue; |
| 7122 | if ($(this).attr('is_user') == 'true') { | 7213 | if ($el.attr('is_user') == 'true') continue; |
| 7123 | return; | 7214 | |
| 7124 | } | ||
| 7125 | if (nameMatch) { | 7215 | if (nameMatch) { |
| 7126 | const previewSrc = $('#avatar_load_preview').attr('src'); | 7216 | const previewSrc = $('#avatar_load_preview').attr('src'); |
| 7127 | const avatar = $(this).find('.avatar img'); | 7217 | const avatar = $el.find('.avatar img'); |
| 7128 | avatar.attr('src', default_avatar); | 7218 | avatar.attr('src', default_avatar); |
| 7129 | await delay(1); | 7219 | await delay(1); |
| 7130 | avatar.attr('src', previewSrc); | 7220 | avatar.attr('src', previewSrc); |
| 7131 | } | 7221 | } |
| 7132 | }); | 7222 | } |
| 7133 | 7223 | ||
| 7134 | console.log('Avatar refreshed'); | 7224 | console.log('Avatar refreshed'); |
| 7135 | } | 7225 | } |
| @@ -7979,7 +8069,7 @@ export async function getChatsFromFiles(data, isGroupChat) { | |||
| 7979 | * response is an object with an `error` property set to `true`. | 8069 | * response is an object with an `error` property set to `true`. |
| 7980 | */ | 8070 | */ |
| 7981 | export async function getPastCharacterChats(characterId = null) { | 8071 | export async function getPastCharacterChats(characterId = null) { |
| 7982 | characterId = characterId ?? this_chid; | 8072 | characterId = characterId ?? parseInt(this_chid); |
| 7983 | if (!characters[characterId]) return []; | 8073 | if (!characters[characterId]) return []; |
| 7984 | 8074 | ||
| 7985 | const response = await fetch('/api/characters/chats', { | 8075 | const response = await fetch('/api/characters/chats', { |
| @@ -8046,9 +8136,7 @@ export async function displayPastChats() { | |||
| 8046 | // UX convenience: Focus the search field when the Manage Chat Files view opens. | 8136 | // UX convenience: Focus the search field when the Manage Chat Files view opens. |
| 8047 | setTimeout(function () { | 8137 | setTimeout(function () { |
| 8048 | const textSearchElement = $('#select_chat_search'); | 8138 | const textSearchElement = $('#select_chat_search'); |
| 8049 | textSearchElement.click(); | 8139 | textSearchElement.trigger('click').trigger('focus').trigger('select'); |
| 8050 | textSearchElement.focus(); | ||
| 8051 | textSearchElement.select(); // select content (if any) for easy erasing | ||
| 8052 | }, 200); | 8140 | }, 200); |
| 8053 | } | 8141 | } |
| 8054 | 8142 | ||
| @@ -8315,11 +8403,10 @@ function select_rm_create({ switchMenu = true } = {}) { | |||
| 8315 | switchMenu && setMenuType('create'); | 8403 | switchMenu && setMenuType('create'); |
| 8316 | 8404 | ||
| 8317 | //console.log('select_rm_Create() -- selected button: '+selected_button); | 8405 | //console.log('select_rm_Create() -- selected button: '+selected_button); |
| 8318 | if (selected_button == 'create') { | 8406 | if (selected_button == 'create' && create_save.avatar) { |
| 8319 | if (create_save.avatar != '') { | 8407 | const addAvatarInput = /** @type {HTMLInputElement} */ ($('#add_avatar_button').get(0)); |
| 8320 | $('#add_avatar_button').get(0).files = create_save.avatar; | 8408 | addAvatarInput.files = create_save.avatar; |
| 8321 | read_avatar_load($('#add_avatar_button').get(0)); | 8409 | read_avatar_load(addAvatarInput); |
| 8322 | } | ||
| 8323 | } | 8410 | } |
| 8324 | 8411 | ||
| 8325 | switchMenu && selectRightMenuWithAnimation('rm_ch_create_block'); | 8412 | switchMenu && selectRightMenuWithAnimation('rm_ch_create_block'); |
| @@ -8445,11 +8532,18 @@ export function updateChatMetadata(newValues, reset) { | |||
| 8445 | chat_metadata = reset ? { ...newValues } : { ...chat_metadata, ...newValues }; | 8532 | chat_metadata = reset ? { ...newValues } : { ...chat_metadata, ...newValues }; |
| 8446 | } | 8533 | } |
| 8447 | 8534 | ||
| 8535 | |||
| 8536 | /** | ||
| 8537 | * Updates the state of the favorite button based on the provided state. | ||
| 8538 | * @param {boolean} state Whether the favorite button should be on or off. | ||
| 8539 | */ | ||
| 8448 | function updateFavButtonState(state) { | 8540 | function updateFavButtonState(state) { |
| 8541 | // Update global state of the flag | ||
| 8542 | // TODO: This is bad and needs to be refactored. | ||
| 8449 | fav_ch_checked = state; | 8543 | fav_ch_checked = state; |
| 8450 | $('#fav_checkbox').val(fav_ch_checked); | 8544 | $('#fav_checkbox').prop('checked', state); |
| 8451 | $('#favorite_button').toggleClass('fav_on', fav_ch_checked); | 8545 | $('#favorite_button').toggleClass('fav_on', state); |
| 8452 | $('#favorite_button').toggleClass('fav_off', !fav_ch_checked); | 8546 | $('#favorite_button').toggleClass('fav_off', !state); |
| 8453 | } | 8547 | } |
| 8454 | 8548 | ||
| 8455 | export async function setScenarioOverride() { | 8549 | export async function setScenarioOverride() { |
| @@ -8566,7 +8660,7 @@ export function showSwipeButtons() { | |||
| 8566 | 8660 | ||
| 8567 | //had to add this to make the swipe counter work | 8661 | //had to add this to make the swipe counter work |
| 8568 | //(copied from the onclick functions for swipe buttons.. | 8662 | //(copied from the onclick functions for swipe buttons.. |
| 8569 | //don't know why the array isn't set for non-swipe messsages in Generate or addOneMessage..) | 8663 | //don't know why the array isn't set for non-swipe messages in Generate or addOneMessage..) |
| 8570 | if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array | 8664 | if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array |
| 8571 | chat[chat.length - 1]['swipe_id'] = 0; // set it to id 0 | 8665 | chat[chat.length - 1]['swipe_id'] = 0; // set it to id 0 |
| 8572 | chat[chat.length - 1]['swipes'] = []; // empty the array | 8666 | chat[chat.length - 1]['swipes'] = []; // empty the array |
| @@ -8765,7 +8859,7 @@ function updateEditArrowClasses() { | |||
| 8765 | export function closeMessageEditor(what = 'all') { | 8859 | export function closeMessageEditor(what = 'all') { |
| 8766 | if (what === 'message' || what === 'all') { | 8860 | if (what === 'message' || what === 'all') { |
| 8767 | if (this_edit_mes_id) { | 8861 | if (this_edit_mes_id) { |
| 8768 | $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).click(); | 8862 | $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).trigger('click'); |
| 8769 | } | 8863 | } |
| 8770 | } | 8864 | } |
| 8771 | if (what === 'reasoning' || what === 'all') { | 8865 | if (what === 'reasoning' || what === 'all') { |
| @@ -8854,7 +8948,8 @@ function openCharacterWorldPopup() { | |||
| 8854 | } | 8948 | } |
| 8855 | 8949 | ||
| 8856 | function onExtraWorldInfoChanged() { | 8950 | function onExtraWorldInfoChanged() { |
| 8857 | const selectedWorlds = $('.character_extra_world_info_selector').val(); | 8951 | const selectorFieldValue = $('.character_extra_world_info_selector').val(); |
| 8952 | const selectedWorlds = Array.isArray(selectorFieldValue) ? selectorFieldValue : []; | ||
| 8858 | let charLore = world_info.charLore ?? []; | 8953 | let charLore = world_info.charLore ?? []; |
| 8859 | 8954 | ||
| 8860 | // TODO: Maybe make this utility function not use the window context? | 8955 | // TODO: Maybe make this utility function not use the window context? |
| @@ -8899,7 +8994,7 @@ function openCharacterWorldPopup() { | |||
| 8899 | // Apped to base dropdown | 8994 | // Apped to base dropdown |
| 8900 | world_names.forEach((item, i) => { | 8995 | world_names.forEach((item, i) => { |
| 8901 | const option = document.createElement('option'); | 8996 | const option = document.createElement('option'); |
| 8902 | option.value = i; | 8997 | option.value = String(i); |
| 8903 | option.innerText = item; | 8998 | option.innerText = item; |
| 8904 | option.selected = item === worldId; | 8999 | option.selected = item === worldId; |
| 8905 | select.append(option); | 9000 | select.append(option); |
| @@ -8911,7 +9006,7 @@ function openCharacterWorldPopup() { | |||
| 8911 | } | 9006 | } |
| 8912 | world_names.forEach((item, i) => { | 9007 | world_names.forEach((item, i) => { |
| 8913 | const option = document.createElement('option'); | 9008 | const option = document.createElement('option'); |
| 8914 | option.value = i; | 9009 | option.value = String(i); |
| 8915 | option.innerText = item; | 9010 | option.innerText = item; |
| 8916 | 9011 | ||
| 8917 | const existingCharLore = world_info.charLore?.find((e) => e.name === getCharaFilename()); | 9012 | const existingCharLore = world_info.charLore?.find((e) => e.name === getCharaFilename()); |
| @@ -9017,7 +9112,7 @@ function addAlternateGreeting(template, greeting, index, getArray, popup) { | |||
| 9017 | */ | 9112 | */ |
| 9018 | async function createOrEditCharacter(e) { | 9113 | async function createOrEditCharacter(e) { |
| 9019 | $('#rm_info_avatar').html(''); | 9114 | $('#rm_info_avatar').html(''); |
| 9020 | const formData = new FormData($('#form_create').get(0)); | 9115 | const formData = new FormData(/** @type {HTMLFormElement} */($('#form_create').get(0))); |
| 9021 | formData.set('fav', String(fav_ch_checked)); | 9116 | formData.set('fav', String(fav_ch_checked)); |
| 9022 | const isNewChat = e instanceof CustomEvent && e.type === 'newChat'; | 9117 | const isNewChat = e instanceof CustomEvent && e.type === 'newChat'; |
| 9023 | 9118 | ||
| @@ -9099,7 +9194,7 @@ async function createOrEditCharacter(e) { | |||
| 9099 | 9194 | ||
| 9100 | $('#character_popup-button-h3').text('Create character'); | 9195 | $('#character_popup-button-h3').text('Create character'); |
| 9101 | 9196 | ||
| 9102 | create_save.avatar = ''; | 9197 | create_save.avatar = null; |
| 9103 | 9198 | ||
| 9104 | $('#add_avatar_button').replaceWith( | 9199 | $('#add_avatar_button').replaceWith( |
| 9105 | $('#add_avatar_button').val('').clone(true), | 9200 | $('#add_avatar_button').val('').clone(true), |
| @@ -9348,13 +9443,13 @@ export function swipe_left(_event, { source, repeated } = {}) { | |||
| 9348 | 9443 | ||
| 9349 | /** | 9444 | /** |
| 9350 | * Handles the swipe to the right event. | 9445 | * Handles the swipe to the right event. |
| 9351 | * @param {JQuery.Event} _event Event. | 9446 | * @param {JQuery.Event} [_event] Event. |
| 9352 | * @param {object} params Additional parameters. | 9447 | * @param {object} params Additional parameters. |
| 9353 | * @param {string} [params.source] The source of the swipe event. | 9448 | * @param {string} [params.source] The source of the swipe event. |
| 9354 | * @param {boolean} [params.repeated] Is the swipe event repeated. | 9449 | * @param {boolean} [params.repeated] Is the swipe event repeated. |
| 9355 | */ | 9450 | */ |
| 9356 | //MARK: swipe_right | 9451 | //MARK: swipe_right |
| 9357 | export function swipe_right(_event, { source, repeated } = {}) { | 9452 | export function swipe_right(_event = null, { source, repeated } = {}) { |
| 9358 | if (chat.length - 1 === Number(this_edit_mes_id)) { | 9453 | if (chat.length - 1 === Number(this_edit_mes_id)) { |
| 9359 | closeMessageEditor(); | 9454 | closeMessageEditor(); |
| 9360 | } | 9455 | } |
| @@ -9366,6 +9461,7 @@ export function swipe_right(_event, { source, repeated } = {}) { | |||
| 9366 | // Make sure ad-hoc changes to extras are saved before swiping away | 9461 | // Make sure ad-hoc changes to extras are saved before swiping away |
| 9367 | syncMesToSwipe(); | 9462 | syncMesToSwipe(); |
| 9368 | 9463 | ||
| 9464 | const isPristine = !chat_metadata?.tainted; | ||
| 9369 | const swipe_duration = 200; | 9465 | const swipe_duration = 200; |
| 9370 | const swipe_range = 700; | 9466 | const swipe_range = 700; |
| 9371 | //console.log(swipe_range); | 9467 | //console.log(swipe_range); |
| @@ -9384,14 +9480,16 @@ export function swipe_right(_event, { source, repeated } = {}) { | |||
| 9384 | }; | 9480 | }; |
| 9385 | //assign swipe info array with last message from chat | 9481 | //assign swipe info array with last message from chat |
| 9386 | } | 9482 | } |
| 9387 | if (chat.length === 1 && chat[0]['swipe_id'] !== undefined && chat[0]['swipe_id'] === chat[0]['swipes'].length - 1) { // if swipe_right is called on the last alternate greeting, loop back around | 9483 | // if swipe_right is called on the last alternate greeting in pristine chats, loop back around |
| 9484 | if (chat.length === 1 && chat[0]['swipe_id'] !== undefined && chat[0]['swipe_id'] === chat[0]['swipes'].length - 1 && isPristine) { | ||
| 9388 | chat[0]['swipe_id'] = 0; | 9485 | chat[0]['swipe_id'] = 0; |
| 9389 | } else { | 9486 | } else { |
| 9390 | // If the user is holding down the key and we're at the last swipe, don't do anything | 9487 | // If the user is holding down the key and we're at the last swipe, don't do anything |
| 9391 | if (source === 'keyboard' && repeated && chat[chat.length - 1].swipe_id === chat[chat.length - 1].swipes.length - 1) { | 9488 | if (source === 'keyboard' && repeated && chat[chat.length - 1].swipe_id === chat[chat.length - 1].swipes.length - 1) { |
| 9392 | return; | 9489 | return; |
| 9393 | } | 9490 | } |
| 9394 | chat[chat.length - 1]['swipe_id']++; // make new slot in array | 9491 | // make new slot in array |
| 9492 | chat[chat.length - 1]['swipe_id']++; | ||
| 9395 | } | 9493 | } |
| 9396 | if (chat[chat.length - 1].extra) { | 9494 | if (chat[chat.length - 1].extra) { |
| 9397 | // if message has memory attached - remove it to allow regen | 9495 | // if message has memory attached - remove it to allow regen |
| @@ -9406,8 +9504,8 @@ export function swipe_right(_event, { source, repeated } = {}) { | |||
| 9406 | if (!Array.isArray(chat[chat.length - 1]['swipe_info'])) { | 9504 | if (!Array.isArray(chat[chat.length - 1]['swipe_info'])) { |
| 9407 | chat[chat.length - 1]['swipe_info'] = []; | 9505 | chat[chat.length - 1]['swipe_info'] = []; |
| 9408 | } | 9506 | } |
| 9409 | //console.log(chat[chat.length-1]['swipes']); | 9507 | //if swipe id of last message is the same as the length of the 'swipes' array and not the greeting |
| 9410 | if (parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length && chat.length !== 1) { //if swipe id of last message is the same as the length of the 'swipes' array and not the greeting | 9508 | if (parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length && (chat.length !== 1 || !isPristine)) { |
| 9411 | delete chat[chat.length - 1].gen_started; | 9509 | delete chat[chat.length - 1].gen_started; |
| 9412 | delete chat[chat.length - 1].gen_finished; | 9510 | delete chat[chat.length - 1].gen_finished; |
| 9413 | run_generate = true; | 9511 | run_generate = true; |
| @@ -9985,16 +10083,21 @@ async function doRenameChat(_, chatName) { | |||
| 9985 | } | 10083 | } |
| 9986 | 10084 | ||
| 9987 | /** | 10085 | /** |
| 9988 | * Renames the currently selected chat. | 10086 | * Renames a group or character chat. |
| 9989 | * @param {string} oldFileName Old name of the chat (no JSONL extension) | 10087 | * @param {object} param Parameters for renaming chat |
| 9990 | * @param {string} newName New name for the chat (no JSONL extension) | 10088 | * @param {string} [param.characterId] Character ID to rename chat for |
| 10089 | * @param {string} [param.groupId] Group ID to rename chat for | ||
| 10090 | * @param {string} param.oldFileName Old name of the chat (no JSONL extension) | ||
| 10091 | * @param {string} param.newFileName New name for the chat (no JSONL extension) | ||
| 10092 | * @param {boolean} [param.loader=true] Whether to show loader during the operation | ||
| 9991 | */ | 10093 | */ |
| 9992 | export async function renameChat(oldFileName, newName) { | 10094 | export async function renameGroupOrCharacterChat({ characterId, groupId, oldFileName, newFileName, loader }) { |
| 10095 | const currentChatId = getCurrentChatId(); | ||
| 9993 | const body = { | 10096 | const body = { |
| 9994 | is_group: !!selected_group, | 10097 | is_group: !!groupId, |
| 9995 | avatar_url: characters[this_chid]?.avatar, | 10098 | avatar_url: characters[characterId]?.avatar, |
| 9996 | original_file: `${oldFileName}.jsonl`, | 10099 | original_file: `${oldFileName}.jsonl`, |
| 9997 | renamed_file: `${newName.trim()}.jsonl`, | 10100 | renamed_file: `${newFileName.trim()}.jsonl`, |
| 9998 | }; | 10101 | }; |
| 9999 | 10102 | ||
| 10000 | if (body.original_file === body.renamed_file) { | 10103 | if (body.original_file === body.renamed_file) { |
| @@ -10007,7 +10110,8 @@ export async function renameChat(oldFileName, newName) { | |||
| 10007 | } | 10110 | } |
| 10008 | 10111 | ||
| 10009 | try { | 10112 | try { |
| 10010 | showLoader(); | 10113 | loader && showLoader(); |
| 10114 | |||
| 10011 | const response = await fetch('/api/chats/rename', { | 10115 | const response = await fetch('/api/chats/rename', { |
| 10012 | method: 'POST', | 10116 | method: 'POST', |
| 10013 | body: JSON.stringify(body), | 10117 | body: JSON.stringify(body), |
| @@ -10025,27 +10129,69 @@ export async function renameChat(oldFileName, newName) { | |||
| 10025 | } | 10129 | } |
| 10026 | 10130 | ||
| 10027 | if (data.sanitizedFileName) { | 10131 | if (data.sanitizedFileName) { |
| 10028 | newName = data.sanitizedFileName; | 10132 | newFileName = data.sanitizedFileName; |
| 10029 | } | 10133 | } |
| 10030 | 10134 | ||
| 10031 | if (selected_group) { | 10135 | if (groupId) { |
| 10032 | await renameGroupChat(selected_group, oldFileName, newName); | 10136 | await renameGroupChat(groupId, oldFileName, newFileName); |
| 10033 | } | 10137 | } |
| 10034 | else { | 10138 | else if (characterId !== undefined && String(characterId) === String(this_chid) && characters[characterId]?.chat === oldFileName) { |
| 10035 | if (characters[this_chid].chat == oldFileName) { | 10139 | characters[characterId].chat = newFileName; |
| 10036 | characters[this_chid].chat = newName; | 10140 | $('#selected_chat_pole').val(characters[characterId].chat); |
| 10037 | $('#selected_chat_pole').val(characters[this_chid].chat); | 10141 | await createOrEditCharacter(); |
| 10038 | await createOrEditCharacter(); | ||
| 10039 | } | ||
| 10040 | } | 10142 | } |
| 10041 | 10143 | ||
| 10042 | await reloadCurrentChat(); | 10144 | if (currentChatId) { |
| 10145 | await reloadCurrentChat(); | ||
| 10146 | } | ||
| 10043 | } catch { | 10147 | } catch { |
| 10044 | hideLoader(); | 10148 | loader && hideLoader(); |
| 10045 | await delay(500); | 10149 | await delay(500); |
| 10046 | await callPopup('An error has occurred. Chat was not renamed.', 'text'); | 10150 | await callGenericPopup('An error has occurred. Chat was not renamed.', POPUP_TYPE.TEXT); |
| 10047 | } finally { | 10151 | } finally { |
| 10048 | hideLoader(); | 10152 | loader && hideLoader(); |
| 10153 | } | ||
| 10154 | } | ||
| 10155 | |||
| 10156 | /** | ||
| 10157 | * Renames the currently selected chat. | ||
| 10158 | * @param {string} oldFileName Old name of the chat (no JSONL extension) | ||
| 10159 | * @param {string} newName New name for the chat (no JSONL extension) | ||
| 10160 | */ | ||
| 10161 | export async function renameChat(oldFileName, newName) { | ||
| 10162 | return await renameGroupOrCharacterChat({ | ||
| 10163 | characterId: this_chid, | ||
| 10164 | groupId: selected_group, | ||
| 10165 | oldFileName: oldFileName, | ||
| 10166 | newFileName: newName, | ||
| 10167 | loader: true, | ||
| 10168 | }); | ||
| 10169 | } | ||
| 10170 | |||
| 10171 | /** | ||
| 10172 | * Forces the update of the chat name for a remote character. | ||
| 10173 | * @param {string|number} characterId Character ID to update chat name for | ||
| 10174 | * @param {string} newName New name for the chat | ||
| 10175 | * @returns {Promise<void>} | ||
| 10176 | */ | ||
| 10177 | export async function updateRemoteChatName(characterId, newName) { | ||
| 10178 | const character = characters[characterId]; | ||
| 10179 | if (!character) { | ||
| 10180 | console.warn(`Character not found for ID: ${characterId}`); | ||
| 10181 | return; | ||
| 10182 | } | ||
| 10183 | character.chat = newName; | ||
| 10184 | const mergeRequest = { | ||
| 10185 | avatar: character.avatar, | ||
| 10186 | chat: newName, | ||
| 10187 | }; | ||
| 10188 | const mergeResponse = await fetch('/api/characters/merge-attributes', { | ||
| 10189 | method: 'POST', | ||
| 10190 | headers: getRequestHeaders(), | ||
| 10191 | body: JSON.stringify(mergeRequest), | ||
| 10192 | }); | ||
| 10193 | if (!mergeResponse.ok) { | ||
| 10194 | console.error('Failed to save extension field', mergeResponse.statusText); | ||
| 10049 | } | 10195 | } |
| 10050 | } | 10196 | } |
| 10051 | 10197 | ||
| @@ -10056,9 +10202,6 @@ async function doGetChatName() { | |||
| 10056 | return getCurrentChatDetails().sessionName; | 10202 | return getCurrentChatDetails().sessionName; |
| 10057 | } | 10203 | } |
| 10058 | 10204 | ||
| 10059 | const isPwaMode = window.navigator.standalone; | ||
| 10060 | if (isPwaMode) { $('body').addClass('PWA'); } | ||
| 10061 | |||
| 10062 | function doCharListDisplaySwitch() { | 10205 | function doCharListDisplaySwitch() { |
| 10063 | power_user.charListGrid = !power_user.charListGrid; | 10206 | power_user.charListGrid = !power_user.charListGrid; |
| 10064 | document.body.classList.toggle('charListGrid', power_user.charListGrid); | 10207 | document.body.classList.toggle('charListGrid', power_user.charListGrid); |
| @@ -10203,86 +10346,43 @@ function doDrawerOpenClick() { | |||
| 10203 | /** | 10346 | /** |
| 10204 | * Event handler to open or close a navbar drawer when a navbar icon is clicked. | 10347 | * Event handler to open or close a navbar drawer when a navbar icon is clicked. |
| 10205 | * Handles click events on .drawer-toggle elements. | 10348 | * Handles click events on .drawer-toggle elements. |
| 10206 | * @returns {void} | 10349 | * @returns {Promise<void>} |
| 10207 | */ | 10350 | */ |
| 10208 | function doNavbarIconClick() { | 10351 | export async function doNavbarIconClick() { |
| 10209 | const icon = $(this).find('.drawer-icon'); | 10352 | const icon = $(this).find('.drawer-icon'); |
| 10210 | const drawer = $(this).parent().find('.drawer-content'); | 10353 | const drawer = $(this).parent().find('.drawer-content'); |
| 10211 | if (drawer.hasClass('resizing')) { return; } | ||
| 10212 | const drawerWasOpenAlready = $(this).parent().find('.drawer-content').hasClass('openDrawer'); | 10354 | const drawerWasOpenAlready = $(this).parent().find('.drawer-content').hasClass('openDrawer'); |
| 10213 | const targetDrawerID = $(this).parent().find('.drawer-content').attr('id'); | 10355 | const targetDrawerID = $(this).parent().find('.drawer-content').attr('id'); |
| 10214 | const pinnedDrawerClicked = drawer.hasClass('pinnedOpen'); | 10356 | |
| 10215 | 10357 | if (!drawerWasOpenAlready) { | |
| 10216 | if (!drawerWasOpenAlready) { //to open the drawer | 10358 | const $openDrawers = $('.openDrawer:not(.pinnedOpen)'); |
| 10217 | $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => { | 10359 | const $openIcons = $('.openIcon:not(.drawerPinnedOpen)'); |
| 10218 | slideToggle(el, { | 10360 | for (const iconEl of $openIcons) { |
| 10219 | ...getSlideToggleOptions(), | 10361 | $(iconEl).toggleClass('closedIcon openIcon'); |
| 10220 | onAnimationEnd: function (el) { | 10362 | } |
| 10221 | el.closest('.drawer-content').classList.remove('resizing'); | 10363 | for (const el of $openDrawers) { |
| 10222 | }, | 10364 | $(el).toggleClass('closedDrawer openDrawer'); |
| 10223 | }); | 10365 | } |
| 10224 | }); | 10366 | if ($openDrawers.length) { |
| 10225 | $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon'); | 10367 | await delay(animation_duration); |
| 10226 | $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer'); | 10368 | } |
| 10227 | icon.toggleClass('openIcon closedIcon'); | 10369 | icon.toggleClass('openIcon closedIcon'); |
| 10228 | drawer.toggleClass('openDrawer closedDrawer'); | 10370 | drawer.toggleClass('openDrawer closedDrawer'); |
| 10229 | 10371 | ||
| 10230 | //console.log(targetDrawerID); | ||
| 10231 | if (targetDrawerID === 'right-nav-panel') { | 10372 | if (targetDrawerID === 'right-nav-panel') { |
| 10232 | $(this).closest('.drawer').find('.drawer-content').addClass('resizing').each((_, el) => { | 10373 | favsToHotswap(); |
| 10233 | slideToggle(el, { | 10374 | $('#rm_print_characters_block').trigger('scroll'); |
| 10234 | ...getSlideToggleOptions(), | ||
| 10235 | elementDisplayStyle: 'flex', | ||
| 10236 | onAnimationEnd: function (el) { | ||
| 10237 | el.closest('.drawer-content').classList.remove('resizing'); | ||
| 10238 | favsToHotswap(); | ||
| 10239 | $('#rm_print_characters_block').trigger('scroll'); | ||
| 10240 | }, | ||
| 10241 | }); | ||
| 10242 | }); | ||
| 10243 | } else { | ||
| 10244 | $(this).closest('.drawer').find('.drawer-content').addClass('resizing').each((_, el) => { | ||
| 10245 | slideToggle(el, { | ||
| 10246 | ...getSlideToggleOptions(), | ||
| 10247 | onAnimationEnd: function (el) { | ||
| 10248 | el.closest('.drawer-content').classList.remove('resizing'); | ||
| 10249 | }, | ||
| 10250 | }); | ||
| 10251 | }); | ||
| 10252 | } | 10375 | } |
| 10253 | 10376 | ||
| 10254 | // Set the height of "autoSetHeight" textareas within the drawer to their scroll height | 10377 | // Set the height of "autoSetHeight" textareas within the drawer to their scroll height |
| 10255 | if (!CSS.supports('field-sizing', 'content')) { | 10378 | if (!CSS.supports('field-sizing', 'content')) { |
| 10256 | $(this).closest('.drawer').find('.drawer-content textarea.autoSetHeight').each(async function () { | 10379 | const textareas = $(this).closest('.drawer').find('.drawer-content textarea.autoSetHeight'); |
| 10257 | await resetScrollHeight($(this)); | 10380 | for (const textarea of textareas) { |
| 10258 | return; | 10381 | await resetScrollHeight($(textarea)); |
| 10259 | }); | 10382 | } |
| 10260 | } | 10383 | } |
| 10261 | 10384 | } else if (drawerWasOpenAlready) { | |
| 10262 | } else if (drawerWasOpenAlready) { //to close manually | ||
| 10263 | icon.toggleClass('closedIcon openIcon'); | 10385 | icon.toggleClass('closedIcon openIcon'); |
| 10264 | |||
| 10265 | if (pinnedDrawerClicked) { | ||
| 10266 | $(drawer).addClass('resizing').each((_, el) => { | ||
| 10267 | slideToggle(el, { | ||
| 10268 | ...getSlideToggleOptions(), | ||
| 10269 | onAnimationEnd: function (el) { | ||
| 10270 | el.classList.remove('resizing'); | ||
| 10271 | }, | ||
| 10272 | }); | ||
| 10273 | }); | ||
| 10274 | } | ||
| 10275 | else { | ||
| 10276 | $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => { | ||
| 10277 | slideToggle(el, { | ||
| 10278 | ...getSlideToggleOptions(), | ||
| 10279 | onAnimationEnd: function (el) { | ||
| 10280 | el.closest('.drawer-content').classList.remove('resizing'); | ||
| 10281 | }, | ||
| 10282 | }); | ||
| 10283 | }); | ||
| 10284 | } | ||
| 10285 | |||
| 10286 | drawer.toggleClass('closedDrawer openDrawer'); | 10386 | drawer.toggleClass('closedDrawer openDrawer'); |
| 10287 | } | 10387 | } |
| 10288 | } | 10388 | } |
| @@ -10686,23 +10786,23 @@ jQuery(async function () { | |||
| 10686 | 10786 | ||
| 10687 | //menu buttons setup | 10787 | //menu buttons setup |
| 10688 | 10788 | ||
| 10689 | $('#rm_button_settings').click(function () { | 10789 | $('#rm_button_settings').on('click', function () { |
| 10690 | selected_button = 'settings'; | 10790 | selected_button = 'settings'; |
| 10691 | selectRightMenuWithAnimation('rm_api_block'); | 10791 | selectRightMenuWithAnimation('rm_api_block'); |
| 10692 | }); | 10792 | }); |
| 10693 | $('#rm_button_characters').click(function () { | 10793 | $('#rm_button_characters').on('click', function () { |
| 10694 | selected_button = 'characters'; | 10794 | selected_button = 'characters'; |
| 10695 | select_rm_characters(); | 10795 | select_rm_characters(); |
| 10696 | }); | 10796 | }); |
| 10697 | $('#rm_button_back').click(function () { | 10797 | $('#rm_button_back').on('click', function () { |
| 10698 | selected_button = 'characters'; | 10798 | selected_button = 'characters'; |
| 10699 | select_rm_characters(); | 10799 | select_rm_characters(); |
| 10700 | }); | 10800 | }); |
| 10701 | $('#rm_button_create').click(function () { | 10801 | $('#rm_button_create').on('click', function () { |
| 10702 | selected_button = 'create'; | 10802 | selected_button = 'create'; |
| 10703 | select_rm_create(); | 10803 | select_rm_create(); |
| 10704 | }); | 10804 | }); |
| 10705 | $('#rm_button_selected_ch').click(function () { | 10805 | $('#rm_button_selected_ch').on('click', function () { |
| 10706 | if (selected_group) { | 10806 | if (selected_group) { |
| 10707 | select_group_chats(selected_group); | 10807 | select_group_chats(selected_group); |
| 10708 | } else { | 10808 | } else { |
| @@ -10797,7 +10897,7 @@ jQuery(async function () { | |||
| 10797 | callPopup('<h3>' + t`Delete the Chat File?` + '</h3>', 'del_chat'); | 10897 | callPopup('<h3>' + t`Delete the Chat File?` + '</h3>', 'del_chat'); |
| 10798 | }); | 10898 | }); |
| 10799 | 10899 | ||
| 10800 | $('#advanced_div').click(function () { | 10900 | $('#advanced_div').on('click', function () { |
| 10801 | if (!is_advanced_char_open) { | 10901 | if (!is_advanced_char_open) { |
| 10802 | is_advanced_char_open = true; | 10902 | is_advanced_char_open = true; |
| 10803 | $('#character_popup').css({ 'display': 'flex', 'opacity': 0.0 }).addClass('open'); | 10903 | $('#character_popup').css({ 'display': 'flex', 'opacity': 0.0 }).addClass('open'); |
| @@ -10812,7 +10912,7 @@ jQuery(async function () { | |||
| 10812 | } | 10912 | } |
| 10813 | }); | 10913 | }); |
| 10814 | 10914 | ||
| 10815 | $('#character_cross').click(function () { | 10915 | $('#character_cross').on('click', function () { |
| 10816 | is_advanced_char_open = false; | 10916 | is_advanced_char_open = false; |
| 10817 | $('#character_popup').transition({ | 10917 | $('#character_popup').transition({ |
| 10818 | opacity: 0, | 10918 | opacity: 0, |
| @@ -10822,12 +10922,12 @@ jQuery(async function () { | |||
| 10822 | setTimeout(function () { $('#character_popup').css('display', 'none'); }, animation_duration); | 10922 | setTimeout(function () { $('#character_popup').css('display', 'none'); }, animation_duration); |
| 10823 | }); | 10923 | }); |
| 10824 | 10924 | ||
| 10825 | $('#character_popup_ok').click(function () { | 10925 | $('#character_popup_ok').on('click', function () { |
| 10826 | is_advanced_char_open = false; | 10926 | is_advanced_char_open = false; |
| 10827 | $('#character_popup').css('display', 'none'); | 10927 | $('#character_popup').css('display', 'none'); |
| 10828 | }); | 10928 | }); |
| 10829 | 10929 | ||
| 10830 | $('#dialogue_popup_ok').click(async function (e, customData) { | 10930 | $('#dialogue_popup_ok').on('click', async function (_e, customData) { |
| 10831 | const fromSlashCommand = customData?.fromSlashCommand || false; | 10931 | const fromSlashCommand = customData?.fromSlashCommand || false; |
| 10832 | dialogueCloseStop = false; | 10932 | dialogueCloseStop = false; |
| 10833 | $('#shadow_popup').transition({ | 10933 | $('#shadow_popup').transition({ |
| @@ -10857,7 +10957,7 @@ jQuery(async function () { | |||
| 10857 | hideLoader(); | 10957 | hideLoader(); |
| 10858 | } else { // Open the history view again after 2 seconds (delay to avoid edge cases for deleting last chat). | 10958 | } else { // Open the history view again after 2 seconds (delay to avoid edge cases for deleting last chat). |
| 10859 | setTimeout(function () { | 10959 | setTimeout(function () { |
| 10860 | $('#option_select_chat').click(); | 10960 | $('#option_select_chat').trigger('click'); |
| 10861 | $('#options').hide(); // hide option popup menu | 10961 | $('#options').hide(); // hide option popup menu |
| 10862 | hideLoader(); | 10962 | hideLoader(); |
| 10863 | }, 2000); | 10963 | }, 2000); |
| @@ -10868,18 +10968,16 @@ jQuery(async function () { | |||
| 10868 | if (popup_type == 'input') { | 10968 | if (popup_type == 'input') { |
| 10869 | dialogueResolve($('#dialogue_popup_input').val()); | 10969 | dialogueResolve($('#dialogue_popup_input').val()); |
| 10870 | $('#dialogue_popup_input').val(''); | 10970 | $('#dialogue_popup_input').val(''); |
| 10871 | |||
| 10872 | } | 10971 | } |
| 10873 | else { | 10972 | else { |
| 10874 | dialogueResolve(true); | 10973 | dialogueResolve(true); |
| 10875 | |||
| 10876 | } | 10974 | } |
| 10877 | 10975 | ||
| 10878 | dialogueResolve = null; | 10976 | dialogueResolve = null; |
| 10879 | } | 10977 | } |
| 10880 | }); | 10978 | }); |
| 10881 | 10979 | ||
| 10882 | $('#dialogue_popup_cancel').click(function (e) { | 10980 | $('#dialogue_popup_cancel').on('click', function (e) { |
| 10883 | dialogueCloseStop = false; | 10981 | dialogueCloseStop = false; |
| 10884 | $('#shadow_popup').transition({ | 10982 | $('#shadow_popup').transition({ |
| 10885 | opacity: 0, | 10983 | opacity: 0, |
| @@ -10892,21 +10990,20 @@ jQuery(async function () { | |||
| 10892 | $('#dialogue_popup').removeClass('large_dialogue_popup'); | 10990 | $('#dialogue_popup').removeClass('large_dialogue_popup'); |
| 10893 | }, animation_duration); | 10991 | }, animation_duration); |
| 10894 | 10992 | ||
| 10895 | //$("#shadow_popup").css("opacity:", 0.0); | ||
| 10896 | popup_type = ''; | 10993 | popup_type = ''; |
| 10897 | 10994 | ||
| 10898 | if (dialogueResolve) { | 10995 | if (dialogueResolve) { |
| 10899 | dialogueResolve(false); | 10996 | dialogueResolve(false); |
| 10900 | dialogueResolve = null; | 10997 | dialogueResolve = null; |
| 10901 | } | 10998 | } |
| 10902 | |||
| 10903 | }); | 10999 | }); |
| 10904 | 11000 | ||
| 10905 | $('#add_avatar_button').change(function () { | 11001 | $('#add_avatar_button').on('change', function () { |
| 10906 | read_avatar_load(this); | 11002 | const inputElement = /** @type {HTMLInputElement} */ (this); |
| 11003 | read_avatar_load(inputElement); | ||
| 10907 | }); | 11004 | }); |
| 10908 | 11005 | ||
| 10909 | $('#form_create').submit(createOrEditCharacter); | 11006 | $('#form_create').on('submit', (e) => createOrEditCharacter(e.originalEvent)); |
| 10910 | 11007 | ||
| 10911 | $('#delete_button').on('click', async function () { | 11008 | $('#delete_button').on('click', async function () { |
| 10912 | if (this_chid === undefined || !characters[this_chid]) { | 11009 | if (this_chid === undefined || !characters[this_chid]) { |
| @@ -10917,7 +11014,7 @@ jQuery(async function () { | |||
| 10917 | let deleteChats = false; | 11014 | let deleteChats = false; |
| 10918 | 11015 | ||
| 10919 | const confirm = await Popup.show.confirm(t`Delete the character?`, await renderTemplateAsync('deleteConfirm'), { | 11016 | const confirm = await Popup.show.confirm(t`Delete the character?`, await renderTemplateAsync('deleteConfirm'), { |
| 10920 | onClose: () => deleteChats = !!$('#del_char_checkbox').prop('checked'), | 11017 | onClose: () => { deleteChats = !!$('#del_char_checkbox').prop('checked'); }, |
| 10921 | }); | 11018 | }); |
| 10922 | if (!confirm) { | 11019 | if (!confirm) { |
| 10923 | return; | 11020 | return; |
| @@ -10977,9 +11074,9 @@ jQuery(async function () { | |||
| 10977 | const oldFileName = oldFileNameFull.replace('.jsonl', ''); | 11074 | const oldFileName = oldFileNameFull.replace('.jsonl', ''); |
| 10978 | 11075 | ||
| 10979 | const popupText = await renderTemplateAsync('chatRename'); | 11076 | const popupText = await renderTemplateAsync('chatRename'); |
| 10980 | const newName = await callPopup(popupText, 'input', oldFileName); | 11077 | const newName = await callGenericPopup(popupText, POPUP_TYPE.INPUT, oldFileName); |
| 10981 | 11078 | ||
| 10982 | if (!newName || newName == oldFileName) { | 11079 | if (!newName || typeof newName !== 'string' || newName == oldFileName) { |
| 10983 | console.log('no new name found, aborting'); | 11080 | console.log('no new name found, aborting'); |
| 10984 | return; | 11081 | return; |
| 10985 | } | 11082 | } |
| @@ -11038,7 +11135,7 @@ jQuery(async function () { | |||
| 11038 | 11135 | ||
| 11039 | /////////////////////////////////////////////////////////////////////////////////// | 11136 | /////////////////////////////////////////////////////////////////////////////////// |
| 11040 | 11137 | ||
| 11041 | $('#api_button').click(function (e) { | 11138 | $('#api_button').on('click', function (e) { |
| 11042 | if ($('#api_url_text').val() != '') { | 11139 | if ($('#api_url_text').val() != '') { |
| 11043 | let value = formatKoboldUrl(String($('#api_url_text').val()).trim()); | 11140 | let value = formatKoboldUrl(String($('#api_url_text').val()).trim()); |
| 11044 | 11141 | ||
| @@ -11179,7 +11276,7 @@ jQuery(async function () { | |||
| 11179 | if ((selected_group || this_chid !== undefined) && !is_send_press) { | 11276 | if ((selected_group || this_chid !== undefined) && !is_send_press) { |
| 11180 | let deleteCurrentChat = false; | 11277 | let deleteCurrentChat = false; |
| 11181 | const result = await Popup.show.confirm(t`Start new chat?`, await renderTemplateAsync('newChatConfirm'), { | 11278 | const result = await Popup.show.confirm(t`Start new chat?`, await renderTemplateAsync('newChatConfirm'), { |
| 11182 | onClose: () => deleteCurrentChat = !!$('#del_chat_checkbox').prop('checked'), | 11279 | onClose: () => { deleteCurrentChat = !!$('#del_chat_checkbox').prop('checked'); }, |
| 11183 | }); | 11280 | }); |
| 11184 | if (!result) { | 11281 | if (!result) { |
| 11185 | return; | 11282 | return; |
| @@ -11283,7 +11380,7 @@ jQuery(async function () { | |||
| 11283 | ////////////////////////////////////////////////////////////////////////////////////////////// | 11380 | ////////////////////////////////////////////////////////////////////////////////////////////// |
| 11284 | 11381 | ||
| 11285 | //functionality for the cancel delete messages button, reverts to normal display of input form | 11382 | //functionality for the cancel delete messages button, reverts to normal display of input form |
| 11286 | $('#dialogue_del_mes_cancel').click(function () { | 11383 | $('#dialogue_del_mes_cancel').on('click', function () { |
| 11287 | $('#dialogue_del_mes').css('display', 'none'); | 11384 | $('#dialogue_del_mes').css('display', 'none'); |
| 11288 | $('#send_form').css('display', css_send_form_display); | 11385 | $('#send_form').css('display', css_send_form_display); |
| 11289 | $('.del_checkbox').each(function () { | 11386 | $('.del_checkbox').each(function () { |
| @@ -11423,7 +11520,7 @@ jQuery(async function () { | |||
| 11423 | 11520 | ||
| 11424 | ////////////////////////////////////////////////////////////// | 11521 | ////////////////////////////////////////////////////////////// |
| 11425 | 11522 | ||
| 11426 | $('#select_chat_cross').click(function () { | 11523 | $('#select_chat_cross').on('click', function () { |
| 11427 | $('#shadow_select_chat_popup').transition({ | 11524 | $('#shadow_select_chat_popup').transition({ |
| 11428 | opacity: 0, | 11525 | opacity: 0, |
| 11429 | duration: animation_duration, | 11526 | duration: animation_duration, |
| @@ -11517,8 +11614,10 @@ jQuery(async function () { | |||
| 11517 | edit_textarea.height(0); | 11614 | edit_textarea.height(0); |
| 11518 | edit_textarea.height(edit_textarea[0].scrollHeight); | 11615 | edit_textarea.height(edit_textarea[0].scrollHeight); |
| 11519 | } | 11616 | } |
| 11520 | edit_textarea.focus(); | 11617 | edit_textarea.trigger('focus'); |
| 11521 | edit_textarea[0].setSelectionRange( //this sets the cursor at the end of the text | 11618 | const textAreaElement = /** @type {HTMLTextAreaElement} */ (edit_textarea[0]); |
| 11619 | // Sets the cursor at the end of the text | ||
| 11620 | textAreaElement.setSelectionRange( | ||
| 11522 | String(edit_textarea.val()).length, | 11621 | String(edit_textarea.val()).length, |
| 11523 | String(edit_textarea.val()).length, | 11622 | String(edit_textarea.val()).length, |
| 11524 | ); | 11623 | ); |
| @@ -11770,8 +11869,8 @@ jQuery(async function () { | |||
| 11770 | //Select chat | 11869 | //Select chat |
| 11771 | 11870 | ||
| 11772 | //**************************CHARACTER IMPORT EXPORT*************************// | 11871 | //**************************CHARACTER IMPORT EXPORT*************************// |
| 11773 | $('#character_import_button').click(function () { | 11872 | $('#character_import_button').on('click', function () { |
| 11774 | $('#character_import_file').click(); | 11873 | $('#character_import_file').trigger('click'); |
| 11775 | }); | 11874 | }); |
| 11776 | 11875 | ||
| 11777 | $('#character_import_file').on('change', async function (e) { | 11876 | $('#character_import_file').on('change', async function (e) { |
| @@ -11839,12 +11938,16 @@ jQuery(async function () { | |||
| 11839 | } | 11938 | } |
| 11840 | }); | 11939 | }); |
| 11841 | //**************************CHAT IMPORT EXPORT*************************// | 11940 | //**************************CHAT IMPORT EXPORT*************************// |
| 11842 | $('#chat_import_button').click(function () { | 11941 | $('#chat_import_button').on('click', function () { |
| 11843 | $('#chat_import_file').click(); | 11942 | $('#chat_import_file').trigger('click'); |
| 11844 | }); | 11943 | }); |
| 11845 | 11944 | ||
| 11846 | $('#chat_import_file').on('change', async function (e) { | 11945 | $('#chat_import_file').on('change', async function (e) { |
| 11847 | const file = e.target.files[0]; | 11946 | const targetElement = /** @type {HTMLInputElement} */ (e.target); |
| 11947 | if (!(targetElement instanceof HTMLInputElement)) { | ||
| 11948 | return; | ||
| 11949 | } | ||
| 11950 | const file = targetElement.files[0]; | ||
| 11848 | 11951 | ||
| 11849 | if (!file) { | 11952 | if (!file) { |
| 11850 | return; | 11953 | return; |
| @@ -11866,7 +11969,7 @@ jQuery(async function () { | |||
| 11866 | const format = ext[1].toLowerCase(); | 11969 | const format = ext[1].toLowerCase(); |
| 11867 | $('#chat_import_file_type').val(format); | 11970 | $('#chat_import_file_type').val(format); |
| 11868 | 11971 | ||
| 11869 | const formData = new FormData($('#form_import_chat').get(0)); | 11972 | const formData = new FormData(/** @type {HTMLFormElement} */($('#form_import_chat').get(0))); |
| 11870 | formData.append('user_name', name1); | 11973 | formData.append('user_name', name1); |
| 11871 | $('#select_chat_div').html(''); | 11974 | $('#select_chat_div').html(''); |
| 11872 | 11975 | ||
| @@ -11877,12 +11980,12 @@ jQuery(async function () { | |||
| 11877 | } | 11980 | } |
| 11878 | }); | 11981 | }); |
| 11879 | 11982 | ||
| 11880 | $('#rm_button_group_chats').click(function () { | 11983 | $('#rm_button_group_chats').on('click', function () { |
| 11881 | selected_button = 'group_chats'; | 11984 | selected_button = 'group_chats'; |
| 11882 | select_group_chats(); | 11985 | select_group_chats(); |
| 11883 | }); | 11986 | }); |
| 11884 | 11987 | ||
| 11885 | $('#rm_button_back_from_group').click(function () { | 11988 | $('#rm_button_back_from_group').on('click', function () { |
| 11886 | selected_button = 'characters'; | 11989 | selected_button = 'characters'; |
| 11887 | select_rm_characters(); | 11990 | select_rm_characters(); |
| 11888 | }); | 11991 | }); |
| @@ -11911,8 +12014,8 @@ jQuery(async function () { | |||
| 11911 | 12014 | ||
| 11912 | $('.drawer-toggle').on('click', doNavbarIconClick); | 12015 | $('.drawer-toggle').on('click', doNavbarIconClick); |
| 11913 | 12016 | ||
| 11914 | $('html').on('touchstart mousedown', function (e) { | 12017 | $('html').on('touchstart mousedown', async function (e) { |
| 11915 | var clickTarget = $(e.target); | 12018 | const clickTarget = $(e.target); |
| 11916 | 12019 | ||
| 11917 | if (isExportPopupOpen | 12020 | if (isExportPopupOpen |
| 11918 | && clickTarget.closest('#export_button').length == 0 | 12021 | && clickTarget.closest('#export_button').length == 0 |
| @@ -11933,33 +12036,26 @@ jQuery(async function () { | |||
| 11933 | '#toast-container', | 12036 | '#toast-container', |
| 11934 | '.select2-results', | 12037 | '.select2-results', |
| 11935 | ]; | 12038 | ]; |
| 12039 | |||
| 11936 | for (const id of forbiddenTargets) { | 12040 | for (const id of forbiddenTargets) { |
| 11937 | if (clickTarget.closest(id).length > 0) { | 12041 | if (clickTarget.closest(id).length > 0) { |
| 11938 | return; | 12042 | return; |
| 11939 | } | 12043 | } |
| 11940 | } | 12044 | } |
| 11941 | 12045 | ||
| 11942 | var targetParentHasOpenDrawer = clickTarget.parents('.openDrawer').length; | 12046 | // This autocloses open drawers that are not pinned if a click happens inside the app which does not target them. |
| 11943 | if (clickTarget.hasClass('drawer-icon') == false && !clickTarget.hasClass('openDrawer')) { | 12047 | const targetParentHasOpenDrawer = clickTarget.parents('.openDrawer').length; |
| 11944 | if ($('.openDrawer').length !== 0) { | 12048 | if (!clickTarget.hasClass('drawer-icon') && !clickTarget.hasClass('openDrawer')) { |
| 11945 | if (targetParentHasOpenDrawer === 0) { | 12049 | const $openDrawers = $('.openDrawer').not('.pinnedOpen'); |
| 11946 | //console.log($('.openDrawer').not('.pinnedOpen').length); | 12050 | if ($openDrawers.length && targetParentHasOpenDrawer === 0) { |
| 11947 | $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => { | 12051 | // Toggle icon and drawer classes |
| 11948 | slideToggle(el, { | 12052 | $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon'); |
| 11949 | ...getSlideToggleOptions(), | 12053 | $openDrawers.toggleClass('closedDrawer openDrawer'); |
| 11950 | onAnimationEnd: (el) => { | ||
| 11951 | el.closest('.drawer-content').classList.remove('resizing'); | ||
| 11952 | }, | ||
| 11953 | }); | ||
| 11954 | }); | ||
| 11955 | $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon'); | ||
| 11956 | $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer'); | ||
| 11957 | } | ||
| 11958 | } | 12054 | } |
| 11959 | } | 12055 | } |
| 11960 | }); | 12056 | }); |
| 11961 | 12057 | ||
| 11962 | $(document).on('click', '.inline-drawer-toggle', function (e) { | 12058 | $(document).on('click', '.inline-drawer-toggle', async function (e) { |
| 11963 | if ($(e.target).hasClass('text_pole')) { | 12059 | if ($(e.target).hasClass('text_pole')) { |
| 11964 | return; | 12060 | return; |
| 11965 | } | 12061 | } |
| @@ -11968,6 +12064,7 @@ jQuery(async function () { | |||
| 11968 | const drawerContent = drawer.find('>.inline-drawer-content'); | 12064 | const drawerContent = drawer.find('>.inline-drawer-content'); |
| 11969 | icon.toggleClass('down up'); | 12065 | icon.toggleClass('down up'); |
| 11970 | icon.toggleClass('fa-circle-chevron-down fa-circle-chevron-up'); | 12066 | icon.toggleClass('fa-circle-chevron-down fa-circle-chevron-up'); |
| 12067 | drawer.trigger('inline-drawer-toggle'); | ||
| 11971 | drawerContent.stop().slideToggle({ | 12068 | drawerContent.stop().slideToggle({ |
| 11972 | complete: () => { | 12069 | complete: () => { |
| 11973 | $(this).css('height', ''); | 12070 | $(this).css('height', ''); |
| @@ -11976,10 +12073,10 @@ jQuery(async function () { | |||
| 11976 | 12073 | ||
| 11977 | // Set the height of "autoSetHeight" textareas within the inline-drawer to their scroll height | 12074 | // Set the height of "autoSetHeight" textareas within the inline-drawer to their scroll height |
| 11978 | if (!CSS.supports('field-sizing', 'content')) { | 12075 | if (!CSS.supports('field-sizing', 'content')) { |
| 11979 | drawerContent.find('textarea.autoSetHeight').each(async function () { | 12076 | const textareas = drawerContent.find('textarea.autoSetHeight'); |
| 11980 | await resetScrollHeight($(this)); | 12077 | for (const textarea of textareas) { |
| 11981 | return; | 12078 | await resetScrollHeight($(textarea)); |
| 11982 | }); | 12079 | } |
| 11983 | } | 12080 | } |
| 11984 | }); | 12081 | }); |
| 11985 | 12082 | ||
| @@ -12064,7 +12161,7 @@ jQuery(async function () { | |||
| 12064 | if (!(e.target instanceof HTMLElement)) return; | 12161 | if (!(e.target instanceof HTMLElement)) return; |
| 12065 | if (e.target.matches('#OpenAllWIEntries')) { | 12162 | if (e.target.matches('#OpenAllWIEntries')) { |
| 12066 | document.querySelectorAll('#world_popup_entries_list .inline-drawer').forEach((/** @type {HTMLElement} */ drawer) => { | 12163 | document.querySelectorAll('#world_popup_entries_list .inline-drawer').forEach((/** @type {HTMLElement} */ drawer) => { |
| 12067 | toggleDrawer(drawer, true); | 12164 | delay(0).then(() => toggleDrawer(drawer, true)); |
| 12068 | }); | 12165 | }); |
| 12069 | } else if (e.target.matches('#CloseAllWIEntries')) { | 12166 | } else if (e.target.matches('#CloseAllWIEntries')) { |
| 12070 | document.querySelectorAll('#world_popup_entries_list .inline-drawer').forEach((/** @type {HTMLElement} */ drawer) => { | 12167 | document.querySelectorAll('#world_popup_entries_list .inline-drawer').forEach((/** @type {HTMLElement} */ drawer) => { |
| @@ -12094,7 +12191,7 @@ jQuery(async function () { | |||
| 12094 | return; | 12191 | return; |
| 12095 | } | 12192 | } |
| 12096 | if (isEditVisible && power_user.auto_save_msg_edits === true) { | 12193 | if (isEditVisible && power_user.auto_save_msg_edits === true) { |
| 12097 | $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_done`).click(); | 12194 | $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_done`).trigger('click'); |
| 12098 | closeMessageEditor('reasoning'); | 12195 | closeMessageEditor('reasoning'); |
| 12099 | $('#send_textarea').focus(); | 12196 | $('#send_textarea').focus(); |
| 12100 | return; | 12197 | return; |
| @@ -12109,7 +12206,8 @@ jQuery(async function () { | |||
| 12109 | }); | 12206 | }); |
| 12110 | 12207 | ||
| 12111 | $('#char-management-dropdown').on('change', async (e) => { | 12208 | $('#char-management-dropdown').on('change', async (e) => { |
| 12112 | let target = $(e.target.selectedOptions).attr('id'); | 12209 | const targetElement = /** @type {HTMLSelectElement} */ (e.target); |
| 12210 | const target = $(targetElement.selectedOptions).attr('id'); | ||
| 12113 | switch (target) { | 12211 | switch (target) { |
| 12114 | case 'set_character_world': | 12212 | case 'set_character_world': |
| 12115 | openCharacterWorldPopup(); | 12213 | openCharacterWorldPopup(); |
| @@ -12257,9 +12355,7 @@ jQuery(async function () { | |||
| 12257 | 12355 | ||
| 12258 | $(document).on('click', '.external_import_button, #external_import_button', async () => { | 12356 | $(document).on('click', '.external_import_button, #external_import_button', async () => { |
| 12259 | const html = await renderTemplateAsync('importCharacters'); | 12357 | const html = await renderTemplateAsync('importCharacters'); |
| 12260 | 12358 | const input = await callGenericPopup(html, POPUP_TYPE.INPUT, '', { allowVerticalScrolling: true, wider: true, okButton: $('#popup_template').attr('popup-button-import'), rows: 4 }); | |
| 12261 | /** @type {string?} */ | ||
| 12262 | const input = await callGenericPopup(html, POPUP_TYPE.INPUT, '', { wider: true, okButton: $('#popup_template').attr('popup-button-import'), rows: 4 }); | ||
| 12263 | 12359 | ||
| 12264 | if (!input) { | 12360 | if (!input) { |
| 12265 | console.debug('Custom content import cancelled'); | 12361 | console.debug('Custom content import cancelled'); |
| @@ -12267,7 +12363,7 @@ jQuery(async function () { | |||
| 12267 | } | 12363 | } |
| 12268 | 12364 | ||
| 12269 | // break input into one input per line | 12365 | // break input into one input per line |
| 12270 | const inputs = input.split('\n').map(x => x.trim()).filter(x => x.length > 0); | 12366 | const inputs = String(input).split('\n').map(x => x.trim()).filter(x => x.length > 0); |
| 12271 | 12367 | ||
| 12272 | for (const url of inputs) { | 12368 | for (const url of inputs) { |
| 12273 | let request; | 12369 | let request; |
| @@ -2,7 +2,6 @@ | |||
| 2 | 2 | ||
| 3 | import { | 3 | import { |
| 4 | characterGroupOverlay, | 4 | characterGroupOverlay, |
| 5 | callPopup, | ||
| 6 | characters, | 5 | characters, |
| 7 | event_types, | 6 | event_types, |
| 8 | eventSource, | 7 | eventSource, |
| @@ -17,6 +16,7 @@ import { | |||
| 17 | import { favsToHotswap } from './RossAscends-mods.js'; | 16 | import { favsToHotswap } from './RossAscends-mods.js'; |
| 18 | import { hideLoader, showLoader } from './loader.js'; | 17 | import { hideLoader, showLoader } from './loader.js'; |
| 19 | import { convertCharacterToPersona } from './personas.js'; | 18 | import { convertCharacterToPersona } from './personas.js'; |
| 19 | import { callGenericPopup, POPUP_TYPE } from './popup.js'; | ||
| 20 | import { createTagInput, getTagKeyForEntity, getTagsList, printTagList, tag_map, compareTagsForSort, removeTagFromMap, importTags, tag_import_setting } from './tags.js'; | 20 | import { createTagInput, getTagKeyForEntity, getTagsList, printTagList, tag_map, compareTagsForSort, removeTagFromMap, importTags, tag_import_setting } from './tags.js'; |
| 21 | 21 | ||
| 22 | /** | 22 | /** |
| @@ -835,12 +835,13 @@ class BulkEditOverlay { | |||
| 835 | */ | 835 | */ |
| 836 | handleContextMenuDelete = () => { | 836 | handleContextMenuDelete = () => { |
| 837 | const characterIds = this.selectedCharacters; | 837 | const characterIds = this.selectedCharacters; |
| 838 | const popupContent = BulkEditOverlay.#getDeletePopupContentHtml(characterIds); | 838 | const popupContent = $(BulkEditOverlay.#getDeletePopupContentHtml(characterIds)); |
| 839 | const promise = callPopup(popupContent, null) | 839 | const checkbox = popupContent.find('#del_char_checkbox'); |
| 840 | const promise = callGenericPopup(popupContent, POPUP_TYPE.CONFIRM) | ||
| 840 | .then((accept) => { | 841 | .then((accept) => { |
| 841 | if (true !== accept) return; | 842 | if (!accept) return; |
| 842 | 843 | ||
| 843 | const deleteChats = document.getElementById('del_char_checkbox').checked ?? false; | 844 | const deleteChats = checkbox.prop('checked') ?? false; |
| 844 | 845 | ||
| 845 | showLoader(); | 846 | showLoader(); |
| 846 | const toast = toastr.info('We\'re deleting your characters, please wait...', 'Working on it'); | 847 | const toast = toastr.info('We\'re deleting your characters, please wait...', 'Working on it'); |
| @@ -1,4 +1,4 @@ | |||
| 1 | import { DOMPurify, Bowser, slideToggle } from '../lib.js'; | 1 | import { DOMPurify, Bowser } from '../lib.js'; |
| 2 | 2 | ||
| 3 | import { | 3 | import { |
| 4 | characters, | 4 | characters, |
| @@ -19,7 +19,7 @@ import { | |||
| 19 | menu_type, | 19 | menu_type, |
| 20 | substituteParams, | 20 | substituteParams, |
| 21 | sendTextareaMessage, | 21 | sendTextareaMessage, |
| 22 | getSlideToggleOptions, | 22 | doNavbarIconClick, |
| 23 | } from '../script.js'; | 23 | } from '../script.js'; |
| 24 | 24 | ||
| 25 | import { | 25 | import { |
| @@ -402,7 +402,8 @@ function RA_autoconnect(PrevApi) { | |||
| 402 | || (secret_state[SECRET_KEYS.OPENROUTER] && oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER) | 402 | || (secret_state[SECRET_KEYS.OPENROUTER] && oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER) |
| 403 | || (secret_state[SECRET_KEYS.AI21] && oai_settings.chat_completion_source == chat_completion_sources.AI21) | 403 | || (secret_state[SECRET_KEYS.AI21] && oai_settings.chat_completion_source == chat_completion_sources.AI21) |
| 404 | || (secret_state[SECRET_KEYS.MAKERSUITE] && oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) | 404 | || (secret_state[SECRET_KEYS.MAKERSUITE] && oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) |
| 405 | || (secret_state[SECRET_KEYS.VERTEXAI] && oai_settings.chat_completion_source == chat_completion_sources.VERTEXAI) | 405 | || (secret_state[SECRET_KEYS.VERTEXAI] && oai_settings.chat_completion_source == chat_completion_sources.VERTEXAI && oai_settings.vertexai_auth_mode === 'express') |
| 406 | || (secret_state[SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT] && oai_settings.chat_completion_source == chat_completion_sources.VERTEXAI && oai_settings.vertexai_auth_mode === 'full') | ||
| 406 | || (secret_state[SECRET_KEYS.MISTRALAI] && oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) | 407 | || (secret_state[SECRET_KEYS.MISTRALAI] && oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) |
| 407 | || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE) | 408 | || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE) |
| 408 | || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) | 409 | || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) |
| @@ -411,6 +412,7 @@ function RA_autoconnect(PrevApi) { | |||
| 411 | || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) | 412 | || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) |
| 412 | || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) | 413 | || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) |
| 413 | || (secret_state[SECRET_KEYS.XAI] && oai_settings.chat_completion_source == chat_completion_sources.XAI) | 414 | || (secret_state[SECRET_KEYS.XAI] && oai_settings.chat_completion_source == chat_completion_sources.XAI) |
| 415 | || (secret_state[SECRET_KEYS.AIMLAPI] && oai_settings.chat_completion_source == chat_completion_sources.AIMLAPI) | ||
| 414 | || (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS) | 416 | || (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS) |
| 415 | || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) | 417 | || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) |
| 416 | ) { | 418 | ) { |
| @@ -472,54 +474,72 @@ const saveUserInputDebounced = debounce(saveUserInput); | |||
| 472 | 474 | ||
| 473 | // Make the DIV element draggable: | 475 | // Make the DIV element draggable: |
| 474 | 476 | ||
| 475 | export function dragElement(elmnt) { | 477 | /** |
| 476 | var isHeaderBeingDragged = false; | 478 | * Make the given element draggable. This is used for Moving UI. |
| 477 | var isMouseDown = false; | 479 | * @param {JQuery} $elmnt - The element to make draggable. |
| 480 | */ | ||
| 481 | export function dragElement($elmnt) { | ||
| 482 | let actionType = null; // "drag" or "resize" | ||
| 483 | let isMouseDown = false; | ||
| 478 | 484 | ||
| 479 | var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; | 485 | let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; |
| 480 | var height, width, top, left, right, bottom, | 486 | let height, width, top, left, right, bottom, |
| 481 | maxX, maxY, winHeight, winWidth, | 487 | maxX, maxY, winHeight, winWidth, |
| 482 | topbar, topBarFirstX, topBarLastY; | 488 | topbar, topBarFirstX, topBarLastY; |
| 483 | 489 | ||
| 484 | var elmntName = elmnt.attr('id'); | 490 | const elmntName = $elmnt.attr('id'); |
| 485 | console.debug(`dragElement called for ${elmntName}`); | ||
| 486 | const elmntNameEscaped = $.escapeSelector(elmntName); | 491 | const elmntNameEscaped = $.escapeSelector(elmntName); |
| 487 | const elmntHeader = $(`#${elmntNameEscaped}header`); | 492 | const $elmntHeader = $(`#${elmntNameEscaped}header`); |
| 488 | 493 | ||
| 489 | if (elmntHeader.length) { | 494 | // Helper: Save position/size to state and emit events |
| 490 | elmntHeader.off('mousedown').on('mousedown', (e) => { //listener for drag handle repositioning | 495 | function savePositionAndSize() { |
| 491 | isHeaderBeingDragged = true; | 496 | if (!power_user.movingUIState[elmntName]) power_user.movingUIState[elmntName] = {}; |
| 492 | isMouseDown = true; | 497 | power_user.movingUIState[elmntName].top = top; |
| 493 | observer.observe(elmnt.get(0), { attributes: true, attributeFilter: ['style'] }); | 498 | power_user.movingUIState[elmntName].left = left; |
| 494 | dragMouseDown(e); | 499 | power_user.movingUIState[elmntName].right = right; |
| 495 | }); | 500 | power_user.movingUIState[elmntName].bottom = bottom; |
| 496 | $(elmnt).off('mousedown').on('mousedown', () => { //listener for resize | 501 | power_user.movingUIState[elmntName].margin = 'unset'; |
| 497 | isMouseDown = true; | 502 | if (actionType === 'resize') { |
| 498 | observer.observe(elmnt.get(0), { attributes: true, attributeFilter: ['style'] }); | 503 | power_user.movingUIState[elmntName].width = width; |
| 499 | }); | 504 | power_user.movingUIState[elmntName].height = height; |
| 505 | eventSource.emit('resizeUI', elmntName); | ||
| 506 | } | ||
| 507 | saveSettingsDebounced(); | ||
| 500 | } | 508 | } |
| 501 | 509 | ||
| 510 | // Helper: Clamp element within viewport | ||
| 511 | function clampToViewport() { | ||
| 512 | if (top <= 0) $elmnt.css('top', '0px'); | ||
| 513 | else if (maxY >= winHeight) $elmnt.css('top', winHeight - maxY + top - 1 + 'px'); | ||
| 514 | if (left <= 0) $elmnt.css('left', '0px'); | ||
| 515 | else if (maxX >= winWidth) $elmnt.css('left', winWidth - maxX + left - 1 + 'px'); | ||
| 516 | } | ||
| 517 | |||
| 518 | // Observer for style changes (position/size) | ||
| 502 | const observer = new MutationObserver((mutations) => { | 519 | const observer = new MutationObserver((mutations) => { |
| 503 | const target = mutations[0].target; | 520 | const $target = $(mutations[0].target); |
| 504 | if (!$(target).is(':visible') //abort if element is invisible | 521 | if ( |
| 505 | || $(target).hasClass('resizing') //being auto-resized by other JS code | 522 | !$target.is(':visible') || |
| 506 | || Number((String(target.height).replace('px', ''))) < 50 //too short | 523 | $target.hasClass('resizing') || |
| 507 | || Number((String(target.width).replace('px', ''))) < 50 //too narrow | 524 | $target.height() < 50 || |
| 508 | || power_user.movingUI === false // if MUI is not turned on | 525 | $target.width() < 50 || |
| 509 | || isMobile() // if it's a mobile screen | 526 | power_user.movingUI === false || |
| 527 | isMobile() || | ||
| 528 | !isMouseDown | ||
| 510 | ) { | 529 | ) { |
| 530 | observer.disconnect(); | ||
| 511 | return; | 531 | return; |
| 512 | } | 532 | } |
| 513 | 533 | ||
| 514 | const style = getComputedStyle(target); | 534 | const style = getComputedStyle($target[0]); |
| 515 | height = parseInt(style.height); | 535 | height = parseInt(style.height); |
| 516 | width = parseInt(style.width); | 536 | width = parseInt(style.width); |
| 517 | top = parseInt(style.top); | 537 | top = parseInt(style.top); |
| 518 | left = parseInt(style.left); | 538 | left = parseInt(style.left); |
| 519 | right = parseInt(style.right); | 539 | right = parseInt(style.right); |
| 520 | bottom = parseInt(style.bottom); | 540 | bottom = parseInt(style.bottom); |
| 521 | maxX = parseInt(width + left); | 541 | maxX = width + left; |
| 522 | maxY = parseInt(height + top); | 542 | maxY = height + top; |
| 523 | winWidth = window.innerWidth; | 543 | winWidth = window.innerWidth; |
| 524 | winHeight = window.innerHeight; | 544 | winHeight = window.innerHeight; |
| 525 | 545 | ||
| @@ -528,182 +548,119 @@ export function dragElement(elmnt) { | |||
| 528 | topBarFirstX = parseInt(topbarstyle.marginInline); | 548 | topBarFirstX = parseInt(topbarstyle.marginInline); |
| 529 | topBarLastY = parseInt(topbarstyle.height); | 549 | topBarLastY = parseInt(topbarstyle.height); |
| 530 | 550 | ||
| 531 | //prepare an empty poweruser object for the item being altered if we don't have one already | 551 | // Prepare state object if missing |
| 532 | if (!power_user.movingUIState[elmntName]) { | 552 | if (!power_user.movingUIState[elmntName]) power_user.movingUIState[elmntName] = {}; |
| 533 | console.debug(`adding config property for ${elmntName}`); | ||
| 534 | power_user.movingUIState[elmntName] = {}; | ||
| 535 | } | ||
| 536 | 553 | ||
| 537 | //handle resizing | 554 | if (actionType === 'resize') { |
| 538 | if (!isHeaderBeingDragged && isMouseDown) { //if user is dragging the resize handle (not in header) | ||
| 539 | let imgHeight, imgWidth, imageAspectRatio; | ||
| 540 | let containerAspectRatio = height / width; | 555 | let containerAspectRatio = height / width; |
| 541 | 556 | if ($elmnt.attr('id').startsWith('zoomFor_')) { | |
| 542 | //force aspect ratio for zoomed avatars | 557 | const zoomedAvatarImage = $elmnt.find('.zoomed_avatar_img'); |
| 543 | if ($(elmnt).attr('id').startsWith('zoomFor_')) { | 558 | const imgHeight = zoomedAvatarImage.height(); |
| 544 | let zoomedAvatarImage = $(elmnt).find('.zoomed_avatar_img'); | 559 | const imgWidth = zoomedAvatarImage.width(); |
| 545 | imgHeight = zoomedAvatarImage.height(); | 560 | const imageAspectRatio = imgHeight / imgWidth; |
| 546 | imgWidth = zoomedAvatarImage.width(); | ||
| 547 | imageAspectRatio = imgHeight / imgWidth; | ||
| 548 | |||
| 549 | // Maintain aspect ratio | ||
| 550 | if (containerAspectRatio !== imageAspectRatio) { | 561 | if (containerAspectRatio !== imageAspectRatio) { |
| 551 | elmnt.css('width', elmnt.width()); | 562 | $elmnt.css('width', $elmnt.width()); |
| 552 | elmnt.css('height', elmnt.width() * imageAspectRatio); | 563 | $elmnt.css('height', $elmnt.width() * imageAspectRatio); |
| 553 | } | 564 | } |
| 554 | 565 | if (top + $elmnt.height() >= winHeight) { | |
| 555 | // Prevent resizing offscreen | 566 | $elmnt.css('height', winHeight - top - 1 + 'px'); |
| 556 | if (top + elmnt.height() >= winHeight) { | 567 | $elmnt.css('width', (winHeight - top - 1) / imageAspectRatio + 'px'); |
| 557 | elmnt.css('height', winHeight - top - 1 + 'px'); | ||
| 558 | elmnt.css('width', (winHeight - top - 1) / imageAspectRatio + 'px'); | ||
| 559 | } | 568 | } |
| 560 | 569 | if (left + $elmnt.width() >= winWidth) { | |
| 561 | if (left + elmnt.width() >= winWidth) { | 570 | $elmnt.css('width', winWidth - left - 1 + 'px'); |
| 562 | elmnt.css('width', winWidth - left - 1 + 'px'); | 571 | $elmnt.css('height', (winWidth - left - 1) * imageAspectRatio + 'px'); |
| 563 | elmnt.css('height', (winWidth - left - 1) * imageAspectRatio + 'px'); | ||
| 564 | } | ||
| 565 | } else { //prevent divs that are not zoomedAvatars from resizing offscreen | ||
| 566 | |||
| 567 | if (top + elmnt.height() >= winHeight) { | ||
| 568 | elmnt.css('height', winHeight - top - 1 + 'px'); | ||
| 569 | } | ||
| 570 | |||
| 571 | if (left + elmnt.width() >= winWidth) { | ||
| 572 | elmnt.css('width', winWidth - left - 1 + 'px'); | ||
| 573 | } | 572 | } |
| 573 | } else { | ||
| 574 | if (top + $elmnt.height() >= winHeight) $elmnt.css('height', winHeight - top - 1 + 'px'); | ||
| 575 | if (left + $elmnt.width() >= winWidth) $elmnt.css('width', winWidth - left - 1 + 'px'); | ||
| 574 | } | 576 | } |
| 575 | |||
| 576 | //prevent resizing from top left into the top bar | ||
| 577 | if (top < topBarLastY && maxX >= topBarFirstX && left <= topBarFirstX) { | 577 | if (top < topBarLastY && maxX >= topBarFirstX && left <= topBarFirstX) { |
| 578 | elmnt.css('width', width - 1 + 'px'); | 578 | $elmnt.css('width', width - 1 + 'px'); |
| 579 | } | 579 | } |
| 580 | 580 | $elmnt.css({ left, top }); | |
| 581 | //set css to prevent weird resize behavior (does not save) | 581 | $elmnt.off('mouseup').on('mouseup', () => { |
| 582 | elmnt.css('left', left); | 582 | if ( |
| 583 | elmnt.css('top', top); | 583 | power_user.movingUIState[elmntName].width === $elmnt.width() && |
| 584 | 584 | power_user.movingUIState[elmntName].height === $elmnt.height() | |
| 585 | //set a listener for mouseup to save new width/height | 585 | ) return; |
| 586 | $(window).off('mouseup').on('mouseup', () => { | 586 | savePositionAndSize(); |
| 587 | console.log(`Saving ${elmntName} Height/Width`); | 587 | observer.disconnect(); |
| 588 | // check if the height or width actually changed | ||
| 589 | if (power_user.movingUIState[elmntName].width === elmnt.width() && power_user.movingUIState[elmntName].height === elmnt.height()) { | ||
| 590 | console.log('no change detected, aborting save'); | ||
| 591 | return; | ||
| 592 | } | ||
| 593 | |||
| 594 | power_user.movingUIState[elmntName].width = width; | ||
| 595 | power_user.movingUIState[elmntName].height = height; | ||
| 596 | eventSource.emit('resizeUI', elmntName); | ||
| 597 | saveSettingsDebounced(); | ||
| 598 | imgHeight = null; | ||
| 599 | imgWidth = null; | ||
| 600 | height = null; | ||
| 601 | width = null; | ||
| 602 | |||
| 603 | containerAspectRatio = null; | ||
| 604 | imageAspectRatio = null; | ||
| 605 | $(window).off('mouseup'); | ||
| 606 | }); | 588 | }); |
| 589 | } else if (actionType === 'drag') { | ||
| 590 | clampToViewport(); | ||
| 607 | } | 591 | } |
| 608 | 592 | ||
| 609 | //only record position changes if header is being dragged | 593 | // Always update position in state |
| 610 | power_user.movingUIState[elmntName].top = top; | 594 | savePositionAndSize(); |
| 611 | power_user.movingUIState[elmntName].left = left; | ||
| 612 | power_user.movingUIState[elmntName].right = right; | ||
| 613 | power_user.movingUIState[elmntName].bottom = bottom; | ||
| 614 | power_user.movingUIState[elmntName].margin = 'unset'; | ||
| 615 | |||
| 616 | //handle dragging hit detection to prevent dragging offscreen | ||
| 617 | if (isHeaderBeingDragged && isMouseDown) { | ||
| 618 | |||
| 619 | if (top <= 0) { | ||
| 620 | elmnt.css('top', '0px'); | ||
| 621 | } else if (maxY >= winHeight) { | ||
| 622 | elmnt.css('top', winHeight - maxY + top - 1 + 'px'); | ||
| 623 | } | ||
| 624 | |||
| 625 | if (left <= 0) { | ||
| 626 | elmnt.css('left', '0px'); | ||
| 627 | } else if (maxX >= winWidth) { | ||
| 628 | elmnt.css('left', winWidth - maxX + left - 1 + 'px'); | ||
| 629 | } | ||
| 630 | } | ||
| 631 | |||
| 632 | // Check if the element header exists and set the reposition listener on the grabber in the header | ||
| 633 | if (elmntHeader.length) { | ||
| 634 | elmntHeader.off('mousedown').on('mousedown', (e) => { | ||
| 635 | dragMouseDown(e); | ||
| 636 | }); | ||
| 637 | } else { //if no header, put the listener on the elmnt itself. | ||
| 638 | elmnt.off('mousedown').on('mousedown', dragMouseDown); | ||
| 639 | } | ||
| 640 | }); | 595 | }); |
| 641 | 596 | ||
| 597 | // Mouse event handlers | ||
| 642 | function dragMouseDown(e) { | 598 | function dragMouseDown(e) { |
| 643 | |||
| 644 | if (e) { | 599 | if (e) { |
| 645 | isHeaderBeingDragged = true; | 600 | actionType = 'drag'; |
| 601 | isMouseDown = true; | ||
| 646 | e.preventDefault(); | 602 | e.preventDefault(); |
| 647 | pos3 = e.clientX; //mouse X at click | 603 | pos3 = e.clientX; |
| 648 | pos4 = e.clientY; //mouse Y at click | 604 | pos4 = e.clientY; |
| 649 | } | 605 | } |
| 650 | $(document).on('mouseup', closeDragElement); | 606 | $(document).on('mouseup', closeDragElement); |
| 651 | $(document).on('mousemove', elementDrag); | 607 | $(document).on('mousemove', elementDrag); |
| 652 | } | 608 | } |
| 653 | 609 | ||
| 654 | function elementDrag(e) { | 610 | function elementDrag(e) { |
| 655 | if (!power_user.movingUIState[elmntName]) { | 611 | if (!power_user.movingUIState[elmntName]) power_user.movingUIState[elmntName] = {}; |
| 656 | power_user.movingUIState[elmntName] = {}; | ||
| 657 | } | ||
| 658 | |||
| 659 | e = e || window.event; | ||
| 660 | e.preventDefault(); | 612 | e.preventDefault(); |
| 661 | 613 | pos1 = pos3 - e.clientX; | |
| 662 | pos1 = pos3 - e.clientX; //X change amt (-1 or 1) | 614 | pos2 = pos4 - e.clientY; |
| 663 | pos2 = pos4 - e.clientY; //Y change amt (-1 or 1) | 615 | pos3 = e.clientX; |
| 664 | pos3 = e.clientX; //new mouse X | 616 | pos4 = e.clientY; |
| 665 | pos4 = e.clientY; //new mouse Y | 617 | $elmnt.attr('data-dragged', 'true'); |
| 666 | 618 | $elmnt.css('left', ($elmnt.offset().left - pos1) + 'px'); | |
| 667 | elmnt.attr('data-dragged', 'true'); | 619 | $elmnt.css('top', ($elmnt.offset().top - pos2) + 'px'); |
| 668 | 620 | $elmnt.css('margin', 'unset'); | |
| 669 | //first set css to computed values to avoid CSS NaN results from 'auto', etc | 621 | $elmnt.css('height', height); |
| 670 | elmnt.css('left', (elmnt.offset().left) + 'px'); | 622 | $elmnt.css('width', width); |
| 671 | elmnt.css('top', (elmnt.offset().top) + 'px'); | ||
| 672 | |||
| 673 | //then update element position styles to account for drag changes | ||
| 674 | elmnt.css('margin', 'unset'); | ||
| 675 | elmnt.css('left', (elmnt.offset().left - pos1) + 'px'); | ||
| 676 | elmnt.css('top', (elmnt.offset().top - pos2) + 'px'); | ||
| 677 | /* elmnt.css('right', ((winWidth - maxX) + 'px')); | ||
| 678 | elmnt.css('bottom', ((winHeight - maxY) + 'px')); */ | ||
| 679 | |||
| 680 | // Height/Width here are for visuals only, and are not saved to settings. | ||
| 681 | // This is required because some divs do hot have a set width/height | ||
| 682 | // and will default to shrink to min value of 100px set in CSS file | ||
| 683 | elmnt.css('height', height); | ||
| 684 | elmnt.css('width', width); | ||
| 685 | return; | ||
| 686 | } | 623 | } |
| 687 | 624 | ||
| 688 | function closeDragElement() { | 625 | function closeDragElement() { |
| 689 | console.debug('drag finished'); | ||
| 690 | isHeaderBeingDragged = false; | ||
| 691 | isMouseDown = false; | 626 | isMouseDown = false; |
| 627 | actionType = null; | ||
| 692 | $(document).off('mouseup', closeDragElement); | 628 | $(document).off('mouseup', closeDragElement); |
| 693 | $(document).off('mousemove', elementDrag); | 629 | $(document).off('mousemove', elementDrag); |
| 694 | $('body').css('overflow', ''); | 630 | $elmnt.attr('data-dragged', 'false'); |
| 695 | // Clear the "data-dragged" attribute | ||
| 696 | elmnt.attr('data-dragged', 'false'); | ||
| 697 | observer.disconnect(); | 631 | observer.disconnect(); |
| 698 | console.debug(`Saving ${elmntName} UI position`); | 632 | savePositionAndSize(); |
| 699 | saveSettingsDebounced(); | 633 | } |
| 700 | top = null; | 634 | |
| 701 | left = null; | 635 | // Setup event listeners |
| 702 | right = null; | 636 | if ($elmntHeader.length) { |
| 703 | bottom = null; | 637 | $elmntHeader.off('mousedown').on('mousedown', (e) => { |
| 704 | maxX = null; | 638 | if ($(e.target).hasClass('drag-grabber')) { |
| 705 | maxY = null; | 639 | actionType = 'drag'; |
| 640 | isMouseDown = true; | ||
| 641 | observer.observe($elmnt[0], { attributes: true, attributeFilter: ['style'] }); | ||
| 642 | dragMouseDown(e); | ||
| 643 | } | ||
| 644 | }); | ||
| 706 | } | 645 | } |
| 646 | |||
| 647 | $elmnt.off('mousedown').on('mousedown', (e) => { | ||
| 648 | const rect = $elmnt[0].getBoundingClientRect(); | ||
| 649 | const resizeMargin = 16; | ||
| 650 | const isNearRight = e.clientX > rect.right - resizeMargin; | ||
| 651 | const isNearBottom = e.clientY > rect.bottom - resizeMargin; | ||
| 652 | if (isNearRight && isNearBottom) { | ||
| 653 | actionType = 'resize'; | ||
| 654 | isMouseDown = true; | ||
| 655 | observer.observe($elmnt[0], { attributes: true, attributeFilter: ['style'] }); | ||
| 656 | } | ||
| 657 | }); | ||
| 658 | |||
| 659 | $elmnt.off('mouseup').on('mouseup', () => { | ||
| 660 | isMouseDown = false; | ||
| 661 | actionType = null; | ||
| 662 | observer.disconnect(); | ||
| 663 | }); | ||
| 707 | } | 664 | } |
| 708 | 665 | ||
| 709 | export async function initMovingUI() { | 666 | export async function initMovingUI() { |
| @@ -774,9 +731,8 @@ export function initRossMods() { | |||
| 774 | $(RightNavDrawerIcon).removeClass('drawerPinnedOpen'); | 731 | $(RightNavDrawerIcon).removeClass('drawerPinnedOpen'); |
| 775 | 732 | ||
| 776 | if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { | 733 | if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { |
| 777 | slideToggle(RightNavPanel, getSlideToggleOptions()); | 734 | const toggle = $('#unimportantYes'); |
| 778 | $(RightNavDrawerIcon).toggleClass('closedIcon openIcon'); | 735 | doNavbarIconClick.call(toggle); |
| 779 | $(RightNavPanel).toggleClass('openDrawer closedDrawer'); | ||
| 780 | } | 736 | } |
| 781 | } | 737 | } |
| 782 | }); | 738 | }); |
| @@ -792,14 +748,13 @@ export function initRossMods() { | |||
| 792 | $(LeftNavDrawerIcon).removeClass('drawerPinnedOpen'); | 748 | $(LeftNavDrawerIcon).removeClass('drawerPinnedOpen'); |
| 793 | 749 | ||
| 794 | if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { | 750 | if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { |
| 795 | slideToggle(LeftNavPanel, getSlideToggleOptions()); | 751 | const toggle = $('#ai-config-button>.drawer-toggle'); |
| 796 | $(LeftNavDrawerIcon).toggleClass('closedIcon openIcon'); | 752 | doNavbarIconClick.call(toggle); |
| 797 | $(LeftNavPanel).toggleClass('openDrawer closedDrawer'); | ||
| 798 | } | 753 | } |
| 799 | } | 754 | } |
| 800 | }); | 755 | }); |
| 801 | 756 | ||
| 802 | $(WIPanelPin).on('click', function () { | 757 | $(WIPanelPin).on('click', async function () { |
| 803 | accountStorage.setItem('WINavLockOn', $(WIPanelPin).prop('checked')); | 758 | accountStorage.setItem('WINavLockOn', $(WIPanelPin).prop('checked')); |
| 804 | if ($(WIPanelPin).prop('checked') == true) { | 759 | if ($(WIPanelPin).prop('checked') == true) { |
| 805 | console.debug('adding pin class to WI'); | 760 | console.debug('adding pin class to WI'); |
| @@ -812,9 +767,8 @@ export function initRossMods() { | |||
| 812 | 767 | ||
| 813 | if ($(WorldInfo).hasClass('openDrawer') && $('.openDrawer').length > 1) { | 768 | if ($(WorldInfo).hasClass('openDrawer') && $('.openDrawer').length > 1) { |
| 814 | console.debug('closing WI after lock removal'); | 769 | console.debug('closing WI after lock removal'); |
| 815 | slideToggle(WorldInfo, getSlideToggleOptions()); | 770 | const toggle = $('#WI-SP-button>.drawer-toggle'); |
| 816 | $(WIDrawerIcon).toggleClass('closedIcon openIcon'); | 771 | doNavbarIconClick.call(toggle); |
| 817 | $(WorldInfo).toggleClass('openDrawer closedDrawer'); | ||
| 818 | } | 772 | } |
| 819 | } | 773 | } |
| 820 | }); | 774 | }); |
| @@ -1,9 +1,11 @@ | |||
| 1 | import { | 1 | import { |
| 2 | MAX_INJECTION_DEPTH, | ||
| 2 | animation_duration, | 3 | animation_duration, |
| 3 | chat_metadata, | 4 | chat_metadata, |
| 4 | eventSource, | 5 | eventSource, |
| 5 | event_types, | 6 | event_types, |
| 6 | extension_prompt_roles, | 7 | extension_prompt_roles, |
| 8 | extension_prompt_types, | ||
| 7 | saveSettingsDebounced, | 9 | saveSettingsDebounced, |
| 8 | this_chid, | 10 | this_chid, |
| 9 | } from '../script.js'; | 11 | } from '../script.js'; |
| @@ -347,7 +349,7 @@ export function setFloatingPrompt() { | |||
| 347 | } | 349 | } |
| 348 | 350 | ||
| 349 | if (lastMessageNumber <= 0 || chat_metadata[metadata_keys.interval] <= 0) { | 351 | if (lastMessageNumber <= 0 || chat_metadata[metadata_keys.interval] <= 0) { |
| 350 | context.setExtensionPrompt(MODULE_NAME, ''); | 352 | context.setExtensionPrompt(MODULE_NAME, '', extension_prompt_types.NONE, MAX_INJECTION_DEPTH); |
| 351 | $('#extension_floating_counter').text('(disabled)'); | 353 | $('#extension_floating_counter').text('(disabled)'); |
| 352 | shouldWIAddPrompt = false; | 354 | shouldWIAddPrompt = false; |
| 353 | return; | 355 | return; |
| @@ -380,7 +382,7 @@ export function setFloatingPrompt() { | |||
| 380 | } | 382 | } |
| 381 | context.setExtensionPrompt( | 383 | context.setExtensionPrompt( |
| 382 | MODULE_NAME, | 384 | MODULE_NAME, |
| 383 | prompt, | 385 | String(prompt), |
| 384 | chat_metadata[metadata_keys.position], | 386 | chat_metadata[metadata_keys.position], |
| 385 | chat_metadata[metadata_keys.depth], | 387 | chat_metadata[metadata_keys.depth], |
| 386 | extension_settings.note.allowWIScan, | 388 | extension_settings.note.allowWIScan, |
| @@ -396,37 +398,38 @@ function onANMenuItemClick() { | |||
| 396 | } | 398 | } |
| 397 | 399 | ||
| 398 | //show AN if it's hidden | 400 | //show AN if it's hidden |
| 399 | if ($('#floatingPrompt').css('display') !== 'flex') { | 401 | const $ANcontainer = $('#floatingPrompt'); |
| 400 | $('#floatingPrompt').addClass('resizing'); | 402 | if ($ANcontainer.css('display') !== 'flex') { |
| 401 | $('#floatingPrompt').css('display', 'flex'); | 403 | $ANcontainer.addClass('resizing'); |
| 402 | $('#floatingPrompt').css('opacity', 0.0); | 404 | $ANcontainer.css('display', 'flex'); |
| 403 | $('#floatingPrompt').transition({ | 405 | $ANcontainer.css('opacity', 0.0); |
| 406 | $ANcontainer.transition({ | ||
| 404 | opacity: 1.0, | 407 | opacity: 1.0, |
| 405 | duration: animation_duration, | 408 | duration: animation_duration, |
| 406 | }, async function () { | 409 | }, async function () { |
| 407 | await delay(50); | 410 | await delay(50); |
| 408 | $('#floatingPrompt').removeClass('resizing'); | 411 | $ANcontainer.removeClass('resizing'); |
| 409 | }); | 412 | }); |
| 410 | 413 | ||
| 411 | //auto-open the main AN inline drawer | 414 | //auto-open the main AN inline drawer |
| 412 | if ($('#ANBlockToggle') | 415 | if ($('#ANBlockToggle') |
| 413 | .siblings('.inline-drawer-content') | 416 | .siblings('.inline-drawer-content') |
| 414 | .css('display') !== 'block') { | 417 | .css('display') !== 'block') { |
| 415 | $('#floatingPrompt').addClass('resizing'); | 418 | $ANcontainer.addClass('resizing'); |
| 416 | $('#ANBlockToggle').click(); | 419 | $('#ANBlockToggle').trigger('click'); |
| 417 | } | 420 | } |
| 418 | } else { | 421 | } else { |
| 419 | //hide AN if it's already displayed | 422 | //hide AN if it's already displayed |
| 420 | $('#floatingPrompt').addClass('resizing'); | 423 | $ANcontainer.addClass('resizing'); |
| 421 | $('#floatingPrompt').transition({ | 424 | $ANcontainer.transition({ |
| 422 | opacity: 0.0, | 425 | opacity: 0.0, |
| 423 | duration: animation_duration, | 426 | duration: animation_duration, |
| 424 | }, async function () { | 427 | }, async function () { |
| 425 | await delay(50); | 428 | await delay(50); |
| 426 | $('#floatingPrompt').removeClass('resizing'); | 429 | $ANcontainer.removeClass('resizing'); |
| 427 | }); | 430 | }); |
| 428 | setTimeout(function () { | 431 | setTimeout(function () { |
| 429 | $('#floatingPrompt').hide(); | 432 | $ANcontainer.hide(); |
| 430 | }, animation_duration); | 433 | }, animation_duration); |
| 431 | } | 434 | } |
| 432 | 435 | ||
| @@ -21,6 +21,14 @@ export const AUTOCOMPLETE_SELECT_KEY = { | |||
| 21 | 'ENTER': 2, // 2^1 | 21 | 'ENTER': 2, // 2^1 |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | /** @readonly */ | ||
| 25 | /** @enum {Number} */ | ||
| 26 | export const AUTOCOMPLETE_STATE = { | ||
| 27 | DISABLED: 0, | ||
| 28 | MIN_LENGTH: 1, | ||
| 29 | ALWAYS: 2, | ||
| 30 | }; | ||
| 31 | |||
| 24 | export class AutoComplete { | 32 | export class AutoComplete { |
| 25 | /**@type {HTMLTextAreaElement|HTMLInputElement}*/ textarea; | 33 | /**@type {HTMLTextAreaElement|HTMLInputElement}*/ textarea; |
| 26 | /**@type {boolean}*/ isFloating = false; | 34 | /**@type {boolean}*/ isFloating = false; |
| @@ -109,20 +117,20 @@ export class AutoComplete { | |||
| 109 | this.updateDetailsPositionDebounced = debounce(this.updateDetailsPosition.bind(this), 10); | 117 | this.updateDetailsPositionDebounced = debounce(this.updateDetailsPosition.bind(this), 10); |
| 110 | this.updateFloatingPositionDebounced = debounce(this.updateFloatingPosition.bind(this), 10); | 118 | this.updateFloatingPositionDebounced = debounce(this.updateFloatingPosition.bind(this), 10); |
| 111 | 119 | ||
| 112 | textarea.addEventListener('input', ()=>{ | 120 | textarea.addEventListener('input', () => { |
| 113 | this.selectionStart = this.textarea.selectionStart; | 121 | this.selectionStart = this.textarea.selectionStart; |
| 114 | if (this.text != this.textarea.value) this.show(true, this.wasForced); | 122 | if (this.text != this.textarea.value) this.show(true, this.wasForced); |
| 115 | }); | 123 | }); |
| 116 | textarea.addEventListener('keydown', (evt)=>this.handleKeyDown(evt)); | 124 | textarea.addEventListener('keydown', (evt) => this.handleKeyDown(evt)); |
| 117 | textarea.addEventListener('click', ()=>{ | 125 | textarea.addEventListener('click', () => { |
| 118 | this.selectionStart = this.textarea.selectionStart; | 126 | this.selectionStart = this.textarea.selectionStart; |
| 119 | if (this.isActive) this.show(); | 127 | if (this.isActive) this.show(); |
| 120 | }); | 128 | }); |
| 121 | textarea.addEventListener('blur', ()=>this.hide()); | 129 | textarea.addEventListener('blur', () => this.hide()); |
| 122 | if (isFloating) { | 130 | if (isFloating) { |
| 123 | textarea.addEventListener('scroll', ()=>this.updateFloatingPositionDebounced()); | 131 | textarea.addEventListener('scroll', () => this.updateFloatingPositionDebounced()); |
| 124 | } | 132 | } |
| 125 | window.addEventListener('resize', ()=>this.updatePositionDebounced()); | 133 | window.addEventListener('resize', () => this.updatePositionDebounced()); |
| 126 | } | 134 | } |
| 127 | 135 | ||
| 128 | /** | 136 | /** |
| @@ -132,9 +140,9 @@ export class AutoComplete { | |||
| 132 | makeItem(option) { | 140 | makeItem(option) { |
| 133 | const li = option.renderItem(); | 141 | const li = option.renderItem(); |
| 134 | // gotta listen to pointerdown (happens before textarea-blur) | 142 | // gotta listen to pointerdown (happens before textarea-blur) |
| 135 | li.addEventListener('pointerdown', (evt)=>{ | 143 | li.addEventListener('pointerdown', (evt) => { |
| 136 | evt.preventDefault(); | 144 | evt.preventDefault(); |
| 137 | this.selectedItem = this.result.find(it=>it.name == li.getAttribute('data-name')); | 145 | this.selectedItem = this.result.find(it => it.name == li.getAttribute('data-name')); |
| 138 | this.select(); | 146 | this.select(); |
| 139 | }); | 147 | }); |
| 140 | return li; | 148 | return li; |
| @@ -149,7 +157,7 @@ export class AutoComplete { | |||
| 149 | const chars = Array.from(item.dom.querySelector('.name').children); | 157 | const chars = Array.from(item.dom.querySelector('.name').children); |
| 150 | switch (this.matchType) { | 158 | switch (this.matchType) { |
| 151 | case 'strict': { | 159 | case 'strict': { |
| 152 | chars.forEach((it, idx)=>{ | 160 | chars.forEach((it, idx) => { |
| 153 | if (idx + item.nameOffset < item.name.length) { | 161 | if (idx + item.nameOffset < item.name.length) { |
| 154 | it.classList.add('matched'); | 162 | it.classList.add('matched'); |
| 155 | } else { | 163 | } else { |
| @@ -160,7 +168,7 @@ export class AutoComplete { | |||
| 160 | } | 168 | } |
| 161 | case 'includes': { | 169 | case 'includes': { |
| 162 | const start = item.name.toLowerCase().search(this.name); | 170 | const start = item.name.toLowerCase().search(this.name); |
| 163 | chars.forEach((it, idx)=>{ | 171 | chars.forEach((it, idx) => { |
| 164 | if (idx + item.nameOffset < start) { | 172 | if (idx + item.nameOffset < start) { |
| 165 | it.classList.remove('matched'); | 173 | it.classList.remove('matched'); |
| 166 | } else if (idx + item.nameOffset < start + item.name.length) { | 174 | } else if (idx + item.nameOffset < start + item.name.length) { |
| @@ -172,18 +180,18 @@ export class AutoComplete { | |||
| 172 | break; | 180 | break; |
| 173 | } | 181 | } |
| 174 | case 'fuzzy': { | 182 | case 'fuzzy': { |
| 175 | item.name.replace(this.fuzzyRegex, (_, ...parts)=>{ | 183 | item.name.replace(this.fuzzyRegex, (_, ...parts) => { |
| 176 | parts.splice(-2, 2); | 184 | parts.splice(-2, 2); |
| 177 | if (parts.length == 2) { | 185 | if (parts.length == 2) { |
| 178 | chars.forEach(c=>c.classList.remove('matched')); | 186 | chars.forEach(c => c.classList.remove('matched')); |
| 179 | } else { | 187 | } else { |
| 180 | let cIdx = item.nameOffset; | 188 | let cIdx = item.nameOffset; |
| 181 | parts.forEach((it, idx)=>{ | 189 | parts.forEach((it, idx) => { |
| 182 | if (it === null || it.length == 0) return ''; | 190 | if (it === null || it.length == 0) return ''; |
| 183 | if (idx % 2 == 1) { | 191 | if (idx % 2 == 1) { |
| 184 | chars.slice(cIdx, cIdx + it.length).forEach(c=>c.classList.add('matched')); | 192 | chars.slice(cIdx, cIdx + it.length).forEach(c => c.classList.add('matched')); |
| 185 | } else { | 193 | } else { |
| 186 | chars.slice(cIdx, cIdx + it.length).forEach(c=>c.classList.remove('matched')); | 194 | chars.slice(cIdx, cIdx + it.length).forEach(c => c.classList.remove('matched')); |
| 187 | } | 195 | } |
| 188 | cIdx += it.length; | 196 | cIdx += it.length; |
| 189 | }); | 197 | }); |
| @@ -230,7 +238,7 @@ export class AutoComplete { | |||
| 230 | if (current.length > 0) { | 238 | if (current.length > 0) { |
| 231 | consecutive.push(current); | 239 | consecutive.push(current); |
| 232 | } | 240 | } |
| 233 | consecutive.sort((a,b)=>b.length - a.length); | 241 | consecutive.sort((a, b) => b.length - a.length); |
| 234 | option.score = new AutoCompleteFuzzyScore(start, consecutive[0]?.length ?? 0); | 242 | option.score = new AutoCompleteFuzzyScore(start, consecutive[0]?.length ?? 0); |
| 235 | return option; | 243 | return option; |
| 236 | } | 244 | } |
| @@ -254,8 +262,7 @@ export class AutoComplete { | |||
| 254 | + this.parserResult.name.length | 262 | + this.parserResult.name.length |
| 255 | + (this.startQuote ? 1 : 0) | 263 | + (this.startQuote ? 1 : 0) |
| 256 | + (this.endQuote ? 1 : 0) | 264 | + (this.endQuote ? 1 : 0) |
| 257 | + 1 | 265 | + 1; |
| 258 | ; | ||
| 259 | } | 266 | } |
| 260 | 267 | ||
| 261 | /** | 268 | /** |
| @@ -344,7 +351,7 @@ export class AutoComplete { | |||
| 344 | 351 | ||
| 345 | if (this.matchType == 'fuzzy') { | 352 | if (this.matchType == 'fuzzy') { |
| 346 | // only build the fuzzy regex if match type is set to fuzzy | 353 | // only build the fuzzy regex if match type is set to fuzzy |
| 347 | this.fuzzyRegex = new RegExp(`^(.*?)${this.name.split('').map(char=>`(${escapeRegex(char)})`).join('(.*?)')}(.*?)$`, 'i'); | 354 | this.fuzzyRegex = new RegExp(`^(.*?)${this.name.split('').map(char => `(${escapeRegex(char)})`).join('(.*?)')}(.*?)$`, 'i'); |
| 348 | } | 355 | } |
| 349 | 356 | ||
| 350 | //TODO maybe move the matchers somewhere else; a single match function? matchType is available as property | 357 | //TODO maybe move the matchers somewhere else; a single match function? matchType is available as property |
| @@ -358,12 +365,12 @@ export class AutoComplete { | |||
| 358 | // filter the list of options by the partial name according to the matching type | 365 | // filter the list of options by the partial name according to the matching type |
| 359 | .filter(it => this.isReplaceable || it.name == '' ? (it.matchProvider ? it.matchProvider(this.name) : matchers[this.matchType](it.name)) : it.name.toLowerCase() == this.name) | 366 | .filter(it => this.isReplaceable || it.name == '' ? (it.matchProvider ? it.matchProvider(this.name) : matchers[this.matchType](it.name)) : it.name.toLowerCase() == this.name) |
| 360 | // remove aliases | 367 | // remove aliases |
| 361 | .filter((it,idx,list) => list.findIndex(opt=>opt.value == it.value) == idx); | 368 | .filter((it, idx, list) => list.findIndex(opt => opt.value == it.value) == idx); |
| 362 | 369 | ||
| 363 | if (this.result.length == 0 && this.effectiveParserResult != this.parserResult && isForced) { | 370 | if (this.result.length == 0 && this.effectiveParserResult != this.parserResult && isForced) { |
| 364 | // no matching secondary results and forced trigger -> show current command details | 371 | // no matching secondary results and forced trigger -> show current command details |
| 365 | this.secondaryParserResult = null; | 372 | this.secondaryParserResult = null; |
| 366 | this.result = [this.effectiveParserResult.optionList.find(it=>it.name == this.effectiveParserResult.name)]; | 373 | this.result = [this.effectiveParserResult.optionList.find(it => it.name == this.effectiveParserResult.name)]; |
| 367 | this.name = this.effectiveParserResult.name; | 374 | this.name = this.effectiveParserResult.name; |
| 368 | this.fuzzyRegex = /(.*)(.*)(.*)/; | 375 | this.fuzzyRegex = /(.*)(.*)(.*)/; |
| 369 | } | 376 | } |
| @@ -387,8 +394,7 @@ export class AutoComplete { | |||
| 387 | return option; | 394 | return option; |
| 388 | }) | 395 | }) |
| 389 | // sort by fuzzy score or alphabetical | 396 | // sort by fuzzy score or alphabetical |
| 390 | .toSorted(this.matchType == 'fuzzy' ? this.fuzzyScoreCompare : (a, b) => a.name.localeCompare(b.name)) | 397 | .toSorted(this.matchType == 'fuzzy' ? this.fuzzyScoreCompare : (a, b) => a.name.localeCompare(b.name)); |
| 391 | ; | ||
| 392 | 398 | ||
| 393 | 399 | ||
| 394 | 400 | ||
| @@ -628,12 +634,12 @@ export class AutoComplete { | |||
| 628 | this.clone.style.position = 'fixed'; | 634 | this.clone.style.position = 'fixed'; |
| 629 | this.clone.style.visibility = 'hidden'; | 635 | this.clone.style.visibility = 'hidden'; |
| 630 | document.body.append(this.clone); | 636 | document.body.append(this.clone); |
| 631 | const mo = new MutationObserver(muts=>{ | 637 | const mo = new MutationObserver(muts => { |
| 632 | if (muts.find(it=>Array.from(it.removedNodes).includes(this.textarea))) { | 638 | if (muts.find(it => Array.from(it.removedNodes).includes(this.textarea))) { |
| 633 | this.clone.remove(); | 639 | this.clone.remove(); |
| 634 | } | 640 | } |
| 635 | }); | 641 | }); |
| 636 | mo.observe(this.textarea.parentElement, { childList:true }); | 642 | mo.observe(this.textarea.parentElement, { childList: true }); |
| 637 | } | 643 | } |
| 638 | this.clone.style.height = `${inputRect.height}px`; | 644 | this.clone.style.height = `${inputRect.height}px`; |
| 639 | this.clone.style.left = `${inputRect.left}px`; | 645 | this.clone.style.left = `${inputRect.left}px`; |
| @@ -685,7 +691,7 @@ export class AutoComplete { | |||
| 685 | this.textarea.selectionDirection = selectionEnd; | 691 | this.textarea.selectionDirection = selectionEnd; |
| 686 | } | 692 | } |
| 687 | this.wasForced = false; | 693 | this.wasForced = false; |
| 688 | this.textarea.dispatchEvent(new Event('input', { bubbles:true })); | 694 | this.textarea.dispatchEvent(new Event('input', { bubbles: true })); |
| 689 | this.onSelect?.(this.selectedItem); | 695 | this.onSelect?.(this.selectedItem); |
| 690 | } | 696 | } |
| 691 | 697 | ||
| @@ -700,7 +706,7 @@ export class AutoComplete { | |||
| 700 | this.selectedItem.dom.classList.add('selected'); | 706 | this.selectedItem.dom.classList.add('selected'); |
| 701 | const rect = this.selectedItem.dom.children[0].getBoundingClientRect(); | 707 | const rect = this.selectedItem.dom.children[0].getBoundingClientRect(); |
| 702 | const rectParent = this.dom.getBoundingClientRect(); | 708 | const rectParent = this.dom.getBoundingClientRect(); |
| 703 | if (rect.top < rectParent.top || rect.bottom > rectParent.bottom ) { | 709 | if (rect.top < rectParent.top || rect.bottom > rectParent.bottom) { |
| 704 | this.dom.scrollTop += rect.top < rectParent.top ? rect.top - rectParent.top : rect.bottom - rectParent.bottom; | 710 | this.dom.scrollTop += rect.top < rectParent.top ? rect.top - rectParent.top : rect.bottom - rectParent.bottom; |
| 705 | } | 711 | } |
| 706 | this.renderDetailsDebounced(); | 712 | this.renderDetailsDebounced(); |
| @@ -809,8 +815,8 @@ export class AutoComplete { | |||
| 809 | } | 815 | } |
| 810 | // await keyup to see if cursor position or text has changed | 816 | // await keyup to see if cursor position or text has changed |
| 811 | const oldText = this.textarea.value; | 817 | const oldText = this.textarea.value; |
| 812 | await new Promise(resolve=>{ | 818 | await new Promise(resolve => { |
| 813 | window.addEventListener('keyup', resolve, { once:true }); | 819 | window.addEventListener('keyup', resolve, { once: true }); |
| 814 | }); | 820 | }); |
| 815 | if (this.selectionStart != this.textarea.selectionStart) { | 821 | if (this.selectionStart != this.textarea.selectionStart) { |
| 816 | this.selectionStart = this.textarea.selectionStart; | 822 | this.selectionStart = this.textarea.selectionStart; |
| @@ -1,20 +1,48 @@ | |||
| 1 | import { Fuse } from '../lib.js'; | 1 | import { Fuse, localforage } from '../lib.js'; |
| 2 | 2 | import { chat_metadata, eventSource, event_types, generateQuietPrompt, getCurrentChatId, getRequestHeaders, getThumbnailUrl, saveSettingsDebounced } from '../script.js'; | |
| 3 | import { callPopup, chat_metadata, eventSource, event_types, generateQuietPrompt, getCurrentChatId, getRequestHeaders, getThumbnailUrl, saveSettingsDebounced } from '../script.js'; | ||
| 4 | import { openThirdPartyExtensionMenu, saveMetadataDebounced } from './extensions.js'; | 3 | import { openThirdPartyExtensionMenu, saveMetadataDebounced } from './extensions.js'; |
| 5 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | 4 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| 6 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | 5 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 7 | import { flashHighlight, stringFormat } from './utils.js'; | 6 | import { createThumbnail, flashHighlight, getBase64Async, stringFormat } from './utils.js'; |
| 8 | import { t } from './i18n.js'; | 7 | import { t } from './i18n.js'; |
| 9 | import { Popup } from './popup.js'; | 8 | import { Popup } from './popup.js'; |
| 10 | 9 | ||
| 11 | const BG_METADATA_KEY = 'custom_background'; | 10 | const BG_METADATA_KEY = 'custom_background'; |
| 12 | const LIST_METADATA_KEY = 'chat_backgrounds'; | 11 | const LIST_METADATA_KEY = 'chat_backgrounds'; |
| 13 | 12 | ||
| 13 | // A single transparent PNG pixel used as a placeholder for errored backgrounds | ||
| 14 | const PNG_PIXEL = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; | ||
| 15 | const PNG_PIXEL_BLOB = new Blob([Uint8Array.from(atob(PNG_PIXEL), c => c.charCodeAt(0))], { type: 'image/png' }); | ||
| 16 | const PLACEHOLDER_IMAGE = `url('data:image/png;base64,${PNG_PIXEL}')`; | ||
| 17 | |||
| 18 | /** | ||
| 19 | * Storage for frontend-generated background thumbnails. | ||
| 20 | * This is used to store thumbnails for backgrounds that cannot be generated on the server. | ||
| 21 | */ | ||
| 22 | const THUMBNAIL_STORAGE = localforage.createInstance({ name: 'SillyTavern_Thumbnails' }); | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Cache for thumbnail blob URLs. | ||
| 26 | * @type {Map<string, string>} | ||
| 27 | */ | ||
| 28 | const THUMBNAIL_BLOBS = new Map(); | ||
| 29 | |||
| 30 | const THUMBNAIL_CONFIG = { | ||
| 31 | width: 160, | ||
| 32 | height: 90, | ||
| 33 | }; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Global IntersectionObserver instance for lazy loading backgrounds | ||
| 37 | * @type {IntersectionObserver|null} | ||
| 38 | */ | ||
| 39 | let lazyLoadObserver = null; | ||
| 40 | |||
| 14 | export let background_settings = { | 41 | export let background_settings = { |
| 15 | name: '__transparent.png', | 42 | name: '__transparent.png', |
| 16 | url: generateUrlParameter('__transparent.png', false), | 43 | url: generateUrlParameter('__transparent.png', false), |
| 17 | fitting: 'classic', | 44 | fitting: 'classic', |
| 45 | animation: false, | ||
| 18 | }; | 46 | }; |
| 19 | 47 | ||
| 20 | export function loadBackgroundSettings(settings) { | 48 | export function loadBackgroundSettings(settings) { |
| @@ -25,16 +53,20 @@ export function loadBackgroundSettings(settings) { | |||
| 25 | if (!backgroundSettings.fitting) { | 53 | if (!backgroundSettings.fitting) { |
| 26 | backgroundSettings.fitting = 'classic'; | 54 | backgroundSettings.fitting = 'classic'; |
| 27 | } | 55 | } |
| 56 | if (!Object.hasOwn(backgroundSettings, 'animation')) { | ||
| 57 | backgroundSettings.animation = false; | ||
| 58 | } | ||
| 28 | setBackground(backgroundSettings.name, backgroundSettings.url); | 59 | setBackground(backgroundSettings.name, backgroundSettings.url); |
| 29 | setFittingClass(backgroundSettings.fitting); | 60 | setFittingClass(backgroundSettings.fitting); |
| 30 | $('#background_fitting').val(backgroundSettings.fitting); | 61 | $('#background_fitting').val(backgroundSettings.fitting); |
| 62 | $('#background_thumbnails_animation').prop('checked', background_settings.animation); | ||
| 31 | } | 63 | } |
| 32 | 64 | ||
| 33 | /** | 65 | /** |
| 34 | * Sets the background for the current chat and adds it to the list of custom backgrounds. | 66 | * Sets the background for the current chat and adds it to the list of custom backgrounds. |
| 35 | * @param {{url: string, path:string}} backgroundInfo | 67 | * @param {{url: string, path:string}} backgroundInfo |
| 36 | */ | 68 | */ |
| 37 | function forceSetBackground(backgroundInfo) { | 69 | async function forceSetBackground(backgroundInfo) { |
| 38 | saveBackgroundMetadata(backgroundInfo.url); | 70 | saveBackgroundMetadata(backgroundInfo.url); |
| 39 | setCustomBackground(); | 71 | setCustomBackground(); |
| 40 | 72 | ||
| @@ -43,7 +75,7 @@ function forceSetBackground(backgroundInfo) { | |||
| 43 | list.push(bg); | 75 | list.push(bg); |
| 44 | chat_metadata[LIST_METADATA_KEY] = list; | 76 | chat_metadata[LIST_METADATA_KEY] = list; |
| 45 | saveMetadataDebounced(); | 77 | saveMetadataDebounced(); |
| 46 | getChatBackgroundsList(); | 78 | await getChatBackgroundsList(); |
| 47 | highlightNewBackground(bg); | 79 | highlightNewBackground(bg); |
| 48 | highlightLockedBackground(); | 80 | highlightLockedBackground(); |
| 49 | } | 81 | } |
| @@ -56,11 +88,11 @@ async function onChatChanged() { | |||
| 56 | unsetCustomBackground(); | 88 | unsetCustomBackground(); |
| 57 | } | 89 | } |
| 58 | 90 | ||
| 59 | getChatBackgroundsList(); | 91 | await getChatBackgroundsList(); |
| 60 | highlightLockedBackground(); | 92 | highlightLockedBackground(); |
| 61 | } | 93 | } |
| 62 | 94 | ||
| 63 | function getChatBackgroundsList() { | 95 | async function getChatBackgroundsList() { |
| 64 | const list = chat_metadata[LIST_METADATA_KEY]; | 96 | const list = chat_metadata[LIST_METADATA_KEY]; |
| 65 | const listEmpty = !Array.isArray(list) || list.length === 0; | 97 | const listEmpty = !Array.isArray(list) || list.length === 0; |
| 66 | 98 | ||
| @@ -72,9 +104,10 @@ function getChatBackgroundsList() { | |||
| 72 | } | 104 | } |
| 73 | 105 | ||
| 74 | for (const bg of list) { | 106 | for (const bg of list) { |
| 75 | const template = getBackgroundFromTemplate(bg, true); | 107 | const template = await getBackgroundFromTemplate(bg, true); |
| 76 | $('#bg_custom_content').append(template); | 108 | $('#bg_custom_content').append(template); |
| 77 | } | 109 | } |
| 110 | activateLazyLoader(); | ||
| 78 | } | 111 | } |
| 79 | 112 | ||
| 80 | function getBackgroundPath(fileUrl) { | 113 | function getBackgroundPath(fileUrl) { |
| @@ -224,7 +257,49 @@ async function onCopyToSystemBackgroundClick(e) { | |||
| 224 | const index = list.indexOf(bgNames.oldBg); | 257 | const index = list.indexOf(bgNames.oldBg); |
| 225 | list.splice(index, 1); | 258 | list.splice(index, 1); |
| 226 | saveMetadataDebounced(); | 259 | saveMetadataDebounced(); |
| 227 | getChatBackgroundsList(); | 260 | await getChatBackgroundsList(); |
| 261 | } | ||
| 262 | |||
| 263 | /** | ||
| 264 | * Gets a thumbnail for the background from storage or fetches it if not available. | ||
| 265 | * It caches the thumbnail in local storage and returns a blob URL for the thumbnail. | ||
| 266 | * If the thumbnail cannot be fetched, it returns a transparent PNG pixel as a fallback. | ||
| 267 | * @param {string} bg Background URL | ||
| 268 | * @returns {Promise<string>} Blob URL of the thumbnail | ||
| 269 | */ | ||
| 270 | async function getThumbnailFromStorage(bg) { | ||
| 271 | const cachedBlobUrl = THUMBNAIL_BLOBS.get(bg); | ||
| 272 | if (cachedBlobUrl) { | ||
| 273 | return cachedBlobUrl; | ||
| 274 | } | ||
| 275 | |||
| 276 | const savedBlob = await THUMBNAIL_STORAGE.getItem(bg); | ||
| 277 | if (savedBlob) { | ||
| 278 | const savedBlobUrl = URL.createObjectURL(savedBlob); | ||
| 279 | THUMBNAIL_BLOBS.set(bg, savedBlobUrl); | ||
| 280 | return savedBlobUrl; | ||
| 281 | } | ||
| 282 | |||
| 283 | try { | ||
| 284 | const response = await fetch(getBackgroundPath(bg), { cache: 'force-cache' }); | ||
| 285 | if (!response.ok) { | ||
| 286 | throw new Error('Fetch failed with status: ' + response.status); | ||
| 287 | } | ||
| 288 | const imageBlob = await response.blob(); | ||
| 289 | const imageBase64 = await getBase64Async(imageBlob); | ||
| 290 | const thumbnailBase64 = await createThumbnail(imageBase64, THUMBNAIL_CONFIG.width, THUMBNAIL_CONFIG.height); | ||
| 291 | const thumbnailBlob = await fetch(thumbnailBase64).then(res => res.blob()); | ||
| 292 | await THUMBNAIL_STORAGE.setItem(bg, thumbnailBlob); | ||
| 293 | const blobUrl = URL.createObjectURL(thumbnailBlob); | ||
| 294 | THUMBNAIL_BLOBS.set(bg, blobUrl); | ||
| 295 | return blobUrl; | ||
| 296 | } catch (error) { | ||
| 297 | console.error('Error fetching thumbnail, fallback image will be used:', error); | ||
| 298 | const fallbackBlob = PNG_PIXEL_BLOB; | ||
| 299 | const fallbackBlobUrl = URL.createObjectURL(fallbackBlob); | ||
| 300 | THUMBNAIL_BLOBS.set(bg, fallbackBlobUrl); | ||
| 301 | return fallbackBlobUrl; | ||
| 302 | } | ||
| 228 | } | 303 | } |
| 229 | 304 | ||
| 230 | /** | 305 | /** |
| @@ -245,7 +320,7 @@ async function getNewBackgroundName(referenceElement) { | |||
| 245 | const fileExtension = oldBg.split('.').pop(); | 320 | const fileExtension = oldBg.split('.').pop(); |
| 246 | const fileNameBase = isCustom ? oldBg.split('/').pop() : oldBg; | 321 | const fileNameBase = isCustom ? oldBg.split('/').pop() : oldBg; |
| 247 | const oldBgExtensionless = fileNameBase.replace(`.${fileExtension}`, ''); | 322 | const oldBgExtensionless = fileNameBase.replace(`.${fileExtension}`, ''); |
| 248 | const newBgExtensionless = await callPopup('<h3>' + t`Enter new background name:` + '</h3>', 'input', oldBgExtensionless); | 323 | const newBgExtensionless = await Popup.show.input(t`Enter new background name:`, null, oldBgExtensionless); |
| 249 | 324 | ||
| 250 | if (!newBgExtensionless) { | 325 | if (!newBgExtensionless) { |
| 251 | console.debug('no new_bg_extensionless'); | 326 | console.debug('no new_bg_extensionless'); |
| @@ -327,7 +402,7 @@ async function onDeleteBackgroundClick(e) { | |||
| 327 | } | 402 | } |
| 328 | 403 | ||
| 329 | if (isCustom) { | 404 | if (isCustom) { |
| 330 | getChatBackgroundsList(); | 405 | await getChatBackgroundsList(); |
| 331 | saveMetadataDebounced(); | 406 | saveMetadataDebounced(); |
| 332 | } | 407 | } |
| 333 | } | 408 | } |
| @@ -372,22 +447,55 @@ export async function getBackgrounds() { | |||
| 372 | const response = await fetch('/api/backgrounds/all', { | 447 | const response = await fetch('/api/backgrounds/all', { |
| 373 | method: 'POST', | 448 | method: 'POST', |
| 374 | headers: getRequestHeaders(), | 449 | headers: getRequestHeaders(), |
| 375 | body: JSON.stringify({ | 450 | body: JSON.stringify({}), |
| 376 | '': '', | ||
| 377 | }), | ||
| 378 | }); | 451 | }); |
| 379 | if (response.ok) { | 452 | if (response.ok) { |
| 380 | const getData = await response.json(); | 453 | const { images, config } = await response.json(); |
| 381 | //background = getData; | 454 | Object.assign(THUMBNAIL_CONFIG, config); |
| 382 | //console.log(getData.length); | ||
| 383 | $('#bg_menu_content').children('div').remove(); | 455 | $('#bg_menu_content').children('div').remove(); |
| 384 | for (const bg of getData) { | 456 | for (const bg of images) { |
| 385 | const template = getBackgroundFromTemplate(bg, false); | 457 | const template = await getBackgroundFromTemplate(bg, false); |
| 386 | $('#bg_menu_content').append(template); | 458 | $('#bg_menu_content').append(template); |
| 387 | } | 459 | } |
| 460 | activateLazyLoader(); | ||
| 388 | } | 461 | } |
| 389 | } | 462 | } |
| 390 | 463 | ||
| 464 | function activateLazyLoader() { | ||
| 465 | // Disconnect previous observer to prevent memory leaks | ||
| 466 | if (lazyLoadObserver) { | ||
| 467 | lazyLoadObserver.disconnect(); | ||
| 468 | lazyLoadObserver = null; | ||
| 469 | } | ||
| 470 | |||
| 471 | const lazyLoadElements = document.querySelectorAll('.lazy-load-background'); | ||
| 472 | |||
| 473 | const options = { | ||
| 474 | root: null, | ||
| 475 | rootMargin: '200px', | ||
| 476 | threshold: 0.01, | ||
| 477 | }; | ||
| 478 | |||
| 479 | lazyLoadObserver = new IntersectionObserver((entries, observer) => { | ||
| 480 | entries.forEach(entry => { | ||
| 481 | if (entry.target instanceof HTMLElement && entry.isIntersecting) { | ||
| 482 | const target = entry.target; | ||
| 483 | const bg = target.getAttribute('bgfile'); | ||
| 484 | const isCustom = target.getAttribute('custom') === 'true'; | ||
| 485 | resolveImageUrl(bg, isCustom) | ||
| 486 | .then(url => { target.style.backgroundImage = url; }) | ||
| 487 | .catch(() => { target.style.backgroundImage = PLACEHOLDER_IMAGE; }); | ||
| 488 | target.classList.remove('lazy-load-background'); | ||
| 489 | observer.unobserve(target); | ||
| 490 | } | ||
| 491 | }); | ||
| 492 | }, options); | ||
| 493 | |||
| 494 | lazyLoadElements.forEach(element => { | ||
| 495 | lazyLoadObserver.observe(element); | ||
| 496 | }); | ||
| 497 | } | ||
| 498 | |||
| 391 | /** | 499 | /** |
| 392 | * Gets the CSS URL of the background | 500 | * Gets the CSS URL of the background |
| 393 | * @param {Element} block | 501 | * @param {Element} block |
| @@ -402,22 +510,41 @@ function generateUrlParameter(bg, isCustom) { | |||
| 402 | } | 510 | } |
| 403 | 511 | ||
| 404 | /** | 512 | /** |
| 513 | * Resolves the image URL for the background. | ||
| 514 | * @param {string} bg Background file name | ||
| 515 | * @param {boolean} isCustom Is a custom background | ||
| 516 | * @returns {Promise<string>} CSS URL of the background | ||
| 517 | */ | ||
| 518 | async function resolveImageUrl(bg, isCustom) { | ||
| 519 | const fileExtension = bg.split('.').pop().toLowerCase(); | ||
| 520 | const isAnimated = ['mp4', 'webp'].includes(fileExtension); | ||
| 521 | const thumbnailUrl = isAnimated && !background_settings.animation | ||
| 522 | ? await getThumbnailFromStorage(bg) | ||
| 523 | : isCustom | ||
| 524 | ? bg | ||
| 525 | : getThumbnailUrl('bg', bg); | ||
| 526 | |||
| 527 | return `url('${thumbnailUrl}')`; | ||
| 528 | } | ||
| 529 | |||
| 530 | /** | ||
| 405 | * Instantiates a background template | 531 | * Instantiates a background template |
| 406 | * @param {string} bg Path to background | 532 | * @param {string} bg Path to background |
| 407 | * @param {boolean} isCustom Whether the background is custom | 533 | * @param {boolean} isCustom Whether the background is custom |
| 408 | * @returns {JQuery<HTMLElement>} Background template | 534 | * @returns {Promise<JQuery<HTMLElement>>} Background template |
| 409 | */ | 535 | */ |
| 410 | function getBackgroundFromTemplate(bg, isCustom) { | 536 | async function getBackgroundFromTemplate(bg, isCustom) { |
| 411 | const template = $('#background_template .bg_example').clone(); | 537 | const template = $('#background_template .bg_example').clone(); |
| 412 | const thumbPath = isCustom ? bg : getThumbnailUrl('bg', bg); | ||
| 413 | const url = generateUrlParameter(bg, isCustom); | 538 | const url = generateUrlParameter(bg, isCustom); |
| 414 | const title = isCustom ? bg.split('/').pop() : bg; | 539 | const title = isCustom ? bg.split('/').pop() : bg; |
| 415 | const friendlyTitle = title.slice(0, title.lastIndexOf('.')); | 540 | const friendlyTitle = title.slice(0, title.lastIndexOf('.')); |
| 541 | |||
| 416 | template.attr('title', title); | 542 | template.attr('title', title); |
| 417 | template.attr('bgfile', bg); | 543 | template.attr('bgfile', bg); |
| 418 | template.attr('custom', String(isCustom)); | 544 | template.attr('custom', String(isCustom)); |
| 419 | template.data('url', url); | 545 | template.data('url', url); |
| 420 | template.css('background-image', `url('${thumbPath}')`); | 546 | template.addClass('lazy-load-background'); |
| 547 | template.css('background-image', PLACEHOLDER_IMAGE); | ||
| 421 | template.find('.BGSampleTitle').text(friendlyTitle); | 548 | template.find('.BGSampleTitle').text(friendlyTitle); |
| 422 | return template; | 549 | return template; |
| 423 | } | 550 | } |
| @@ -437,6 +564,12 @@ async function delBackground(bg) { | |||
| 437 | bg: bg, | 564 | bg: bg, |
| 438 | }), | 565 | }), |
| 439 | }); | 566 | }); |
| 567 | |||
| 568 | await THUMBNAIL_STORAGE.removeItem(bg); | ||
| 569 | if (THUMBNAIL_BLOBS.has(bg)) { | ||
| 570 | URL.revokeObjectURL(THUMBNAIL_BLOBS.get(bg)); | ||
| 571 | THUMBNAIL_BLOBS.delete(bg); | ||
| 572 | } | ||
| 440 | } | 573 | } |
| 441 | 574 | ||
| 442 | async function onBackgroundUploadSelected() { | 575 | async function onBackgroundUploadSelected() { |
| @@ -572,17 +705,20 @@ export function initBackgrounds() { | |||
| 572 | $('#auto_background').on('click', autoBackgroundCommand); | 705 | $('#auto_background').on('click', autoBackgroundCommand); |
| 573 | $('#add_bg_button').on('change', onBackgroundUploadSelected); | 706 | $('#add_bg_button').on('change', onBackgroundUploadSelected); |
| 574 | $('#bg-filter').on('input', onBackgroundFilterInput); | 707 | $('#bg-filter').on('input', onBackgroundFilterInput); |
| 575 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'lockbg', | 708 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 709 | name: 'lockbg', | ||
| 576 | callback: () => onLockBackgroundClick(new CustomEvent('click')), | 710 | callback: () => onLockBackgroundClick(new CustomEvent('click')), |
| 577 | aliases: ['bglock'], | 711 | aliases: ['bglock'], |
| 578 | helpString: 'Locks a background for the currently selected chat', | 712 | helpString: 'Locks a background for the currently selected chat', |
| 579 | })); | 713 | })); |
| 580 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'unlockbg', | 714 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 715 | name: 'unlockbg', | ||
| 581 | callback: () => onUnlockBackgroundClick(new CustomEvent('click')), | 716 | callback: () => onUnlockBackgroundClick(new CustomEvent('click')), |
| 582 | aliases: ['bgunlock'], | 717 | aliases: ['bgunlock'], |
| 583 | helpString: 'Unlocks a background for the currently selected chat', | 718 | helpString: 'Unlocks a background for the currently selected chat', |
| 584 | })); | 719 | })); |
| 585 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'autobg', | 720 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 721 | name: 'autobg', | ||
| 586 | callback: autoBackgroundCommand, | 722 | callback: autoBackgroundCommand, |
| 587 | aliases: ['bgauto'], | 723 | aliases: ['bgauto'], |
| 588 | helpString: 'Automatically changes the background based on the chat context using the AI request prompt', | 724 | helpString: 'Automatically changes the background based on the chat context using the AI request prompt', |
| @@ -593,4 +729,13 @@ export function initBackgrounds() { | |||
| 593 | setFittingClass(background_settings.fitting); | 729 | setFittingClass(background_settings.fitting); |
| 594 | saveSettingsDebounced(); | 730 | saveSettingsDebounced(); |
| 595 | }); | 731 | }); |
| 732 | |||
| 733 | $('#background_thumbnails_animation').on('input', async function () { | ||
| 734 | background_settings.animation = !!$(this).prop('checked'); | ||
| 735 | saveSettingsDebounced(); | ||
| 736 | |||
| 737 | // Refresh background thumbnails | ||
| 738 | await getBackgrounds(); | ||
| 739 | await onChatChanged(); | ||
| 740 | }); | ||
| 596 | } | 741 | } |
| @@ -14,7 +14,6 @@ import { | |||
| 14 | } from '../script.js'; | 14 | } from '../script.js'; |
| 15 | import { humanizedDateTime } from './RossAscends-mods.js'; | 15 | import { humanizedDateTime } from './RossAscends-mods.js'; |
| 16 | import { | 16 | import { |
| 17 | getGroupPastChats, | ||
| 18 | group_activation_strategy, | 17 | group_activation_strategy, |
| 19 | groups, | 18 | groups, |
| 20 | openGroupById, | 19 | openGroupById, |
| @@ -40,22 +39,42 @@ import { | |||
| 40 | 39 | ||
| 41 | const bookmarkNameToken = 'Checkpoint #'; | 40 | const bookmarkNameToken = 'Checkpoint #'; |
| 42 | 41 | ||
| 42 | /** | ||
| 43 | * Gets the names of existing chats for the current character or group. | ||
| 44 | * @returns {Promise<string[]>} - Returns a promise that resolves to an array of existing chat names. | ||
| 45 | */ | ||
| 43 | async function getExistingChatNames() { | 46 | async function getExistingChatNames() { |
| 44 | if (selected_group) { | 47 | if (selected_group) { |
| 45 | const data = await getGroupPastChats(selected_group); | 48 | const group = groups.find(x => x.id == selected_group); |
| 46 | return data.map(x => x.file_name); | 49 | if (group && Array.isArray(group.chats)) { |
| 47 | } else { | 50 | return [...group.chats]; |
| 48 | const response = await fetch('/api/characters/chats', { | ||
| 49 | method: 'POST', | ||
| 50 | headers: getRequestHeaders(), | ||
| 51 | body: JSON.stringify({ avatar_url: characters[this_chid].avatar }), | ||
| 52 | }); | ||
| 53 | |||
| 54 | if (response.ok) { | ||
| 55 | const data = await response.json(); | ||
| 56 | return Object.values(data).map(x => x.file_name.replace('.jsonl', '')); | ||
| 57 | } | 51 | } |
| 52 | |||
| 53 | return []; | ||
| 58 | } | 54 | } |
| 55 | |||
| 56 | if (this_chid === undefined) { | ||
| 57 | return []; | ||
| 58 | } | ||
| 59 | |||
| 60 | const character = characters[this_chid]; | ||
| 61 | if (!character) { | ||
| 62 | return []; | ||
| 63 | } | ||
| 64 | |||
| 65 | const response = await fetch('/api/characters/chats', { | ||
| 66 | method: 'POST', | ||
| 67 | headers: getRequestHeaders(), | ||
| 68 | body: JSON.stringify({ avatar_url: character.avatar, simple: true }), | ||
| 69 | }); | ||
| 70 | |||
| 71 | if (response.ok) { | ||
| 72 | const data = await response.json(); | ||
| 73 | const chats = Object.values(data).map(x => x.file_name.replace('.jsonl', '')); | ||
| 74 | return [...chats]; | ||
| 75 | } | ||
| 76 | |||
| 77 | return []; | ||
| 59 | } | 78 | } |
| 60 | 79 | ||
| 61 | async function getBookmarkName({ isReplace = false, forceName = null } = {}) { | 80 | async function getBookmarkName({ isReplace = false, forceName = null } = {}) { |
| @@ -211,6 +211,12 @@ export async function populateFileAttachment(message, inputId = 'file_form_input | |||
| 211 | const imageUrl = await saveBase64AsFile(base64Data, name2, fileNamePrefix, extension); | 211 | const imageUrl = await saveBase64AsFile(base64Data, name2, fileNamePrefix, extension); |
| 212 | message.extra.image = imageUrl; | 212 | message.extra.image = imageUrl; |
| 213 | message.extra.inline_image = true; | 213 | message.extra.inline_image = true; |
| 214 | } | ||
| 215 | // If file is video | ||
| 216 | else if (file.type.startsWith('video/')) { | ||
| 217 | const extension = file.type.split('/')[1]; | ||
| 218 | const videoUrl = await saveBase64AsFile(base64Data, name2, fileNamePrefix, extension); | ||
| 219 | message.extra.video = videoUrl; | ||
| 214 | } else { | 220 | } else { |
| 215 | const uniqueFileName = `${fileNamePrefix}.txt`; | 221 | const uniqueFileName = `${fileNamePrefix}.txt`; |
| 216 | 222 | ||
| @@ -1240,7 +1246,7 @@ async function openAttachmentManager() { | |||
| 1240 | 1246 | ||
| 1241 | return () => { | 1247 | return () => { |
| 1242 | modalButtonData.forEach(p => { | 1248 | modalButtonData.forEach(p => { |
| 1243 | const { popper,bodyListener } = p; | 1249 | const { popper, bodyListener } = p; |
| 1244 | popper.destroy(); | 1250 | popper.destroy(); |
| 1245 | document.body.removeEventListener('click', bodyListener); | 1251 | document.body.removeEventListener('click', bodyListener); |
| 1246 | }); | 1252 | }); |
| @@ -279,9 +279,9 @@ export class TextCompletionService { | |||
| 279 | instructPreset, | 279 | instructPreset, |
| 280 | ); | 280 | ); |
| 281 | } else { // e.g. "<|im_start|>assistant: Hello, my name is" | 281 | } else { // e.g. "<|im_start|>assistant: Hello, my name is" |
| 282 | const overridenInstructPreset = structuredClone(instructPreset); | 282 | const overriddenInstructPreset = structuredClone(instructPreset); |
| 283 | overridenInstructPreset.output_suffix = ''; | 283 | overriddenInstructPreset.output_suffix = ''; |
| 284 | overridenInstructPreset.wrap = false; | 284 | overriddenInstructPreset.wrap = false; |
| 285 | messageContent = formatInstructModeChat( | 285 | messageContent = formatInstructModeChat( |
| 286 | message.role, | 286 | message.role, |
| 287 | message.content, | 287 | message.content, |
| @@ -291,7 +291,7 @@ export class TextCompletionService { | |||
| 291 | undefined, | 291 | undefined, |
| 292 | undefined, | 292 | undefined, |
| 293 | undefined, | 293 | undefined, |
| 294 | overridenInstructPreset, | 294 | overriddenInstructPreset, |
| 295 | ); | 295 | ); |
| 296 | } | 296 | } |
| 297 | } | 297 | } |
| @@ -0,0 +1,393 @@ | |||
| 1 | import { getRequestHeaders } from '../script.js'; | ||
| 2 | import { t } from './i18n.js'; | ||
| 3 | import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js'; | ||
| 4 | import { renderTemplateAsync } from './templates.js'; | ||
| 5 | import { humanFileSize, timestampToMoment } from './utils.js'; | ||
| 6 | |||
| 7 | /** | ||
| 8 | * @typedef {object} DataMaidReportResult | ||
| 9 | * @property {import('../../src/endpoints/data-maid.js').DataMaidSanitizedReport} report - The sanitized report of the Data Maid. | ||
| 10 | * @property {string} token - The token to use for the Data Maid report. | ||
| 11 | */ | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Data Maid Dialog class for managing the cleanup dialog interface. | ||
| 15 | */ | ||
| 16 | class DataMaidDialog { | ||
| 17 | constructor() { | ||
| 18 | this.token = null; | ||
| 19 | this.container = null; | ||
| 20 | this.isScanning = false; | ||
| 21 | |||
| 22 | this.DATA_MAID_CATEGORIES = { | ||
| 23 | files: { | ||
| 24 | name: t`Files`, | ||
| 25 | description: t`Files that are not associated with chat messages or Data Bank. WILL DELETE MANUAL UPLOADS!`, | ||
| 26 | }, | ||
| 27 | images: { | ||
| 28 | name: t`Images`, | ||
| 29 | description: t`Images that are not associated with chat messages. WILL DELETE MANUAL UPLOADS!`, | ||
| 30 | }, | ||
| 31 | chats: { | ||
| 32 | name: t`Chats`, | ||
| 33 | description: t`Chat files associated with deleted characters.`, | ||
| 34 | }, | ||
| 35 | groupChats: { | ||
| 36 | name: t`Group Chats`, | ||
| 37 | description: t`Chat files associated with deleted groups.`, | ||
| 38 | }, | ||
| 39 | avatarThumbnails: { | ||
| 40 | name: t`Avatar Thumbnails`, | ||
| 41 | description: t`Thumbnails for avatars of missing or deleted characters.`, | ||
| 42 | }, | ||
| 43 | backgroundThumbnails: { | ||
| 44 | name: t`Background Thumbnails`, | ||
| 45 | description: t`Thumbnails for missing or deleted backgrounds.`, | ||
| 46 | }, | ||
| 47 | chatBackups: { | ||
| 48 | name: t`Chat Backups`, | ||
| 49 | description: t`Automatically generated chat backups.`, | ||
| 50 | }, | ||
| 51 | settingsBackups: { | ||
| 52 | name: t`Settings Backups`, | ||
| 53 | description: t`Automatically generated settings backups.`, | ||
| 54 | }, | ||
| 55 | }; | ||
| 56 | } | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Returns a promise that resolves to the Data Maid report. | ||
| 60 | * @returns {Promise<DataMaidReportResult>} | ||
| 61 | * @private | ||
| 62 | */ | ||
| 63 | async getReport() { | ||
| 64 | const response = await fetch('/api/data-maid/report', { | ||
| 65 | method: 'POST', | ||
| 66 | headers: getRequestHeaders(), | ||
| 67 | }); | ||
| 68 | |||
| 69 | if (!response.ok) { | ||
| 70 | throw new Error(`Error fetching Data Maid report: ${response.statusText}`); | ||
| 71 | } | ||
| 72 | |||
| 73 | return await response.json(); | ||
| 74 | } | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Finalizes the Data Maid process by sending a request to the server. | ||
| 78 | * @returns {Promise<void>} | ||
| 79 | * @private | ||
| 80 | */ | ||
| 81 | async finalize() { | ||
| 82 | const response = await fetch('/api/data-maid/finalize', { | ||
| 83 | method: 'POST', | ||
| 84 | headers: getRequestHeaders(), | ||
| 85 | body: JSON.stringify({ token: this.token }), | ||
| 86 | }); | ||
| 87 | |||
| 88 | if (!response.ok) { | ||
| 89 | throw new Error(`Error finalizing Data Maid: ${response.statusText}`); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | /** | ||
| 94 | * Sets up the dialog UI elements and event listeners. | ||
| 95 | * @private | ||
| 96 | */ | ||
| 97 | async setupDialogUI() { | ||
| 98 | const template = await renderTemplateAsync('dataMaidDialog'); | ||
| 99 | this.container = document.createElement('div'); | ||
| 100 | this.container.classList.add('dataMaidDialogContainer'); | ||
| 101 | this.container.innerHTML = template; | ||
| 102 | |||
| 103 | const startButton = this.container.querySelector('.dataMaidStartButton'); | ||
| 104 | startButton.addEventListener('click', () => this.handleScanClick()); | ||
| 105 | } | ||
| 106 | |||
| 107 | /** | ||
| 108 | * Handles the scan button click event. | ||
| 109 | * @private | ||
| 110 | */ | ||
| 111 | async handleScanClick() { | ||
| 112 | if (this.isScanning) { | ||
| 113 | toastr.warning(t`The scan is already running. Please wait for it to finish.`); | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | |||
| 117 | try { | ||
| 118 | const resultsList = this.container.querySelector('.dataMaidResultsList'); | ||
| 119 | resultsList.innerHTML = ''; | ||
| 120 | this.showSpinner(); | ||
| 121 | this.isScanning = true; | ||
| 122 | |||
| 123 | const report = await this.getReport(); | ||
| 124 | |||
| 125 | this.hideSpinner(); | ||
| 126 | await this.renderReport(report, resultsList); | ||
| 127 | this.token = report.token; | ||
| 128 | } catch (error) { | ||
| 129 | this.hideSpinner(); | ||
| 130 | toastr.error(t`An error has occurred. Check the console for details.`); | ||
| 131 | console.error('Error generating Data Maid report:', error); | ||
| 132 | } finally { | ||
| 133 | this.isScanning = false; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | /** | ||
| 138 | * Shows the loading spinner and hides the placeholder. | ||
| 139 | * @private | ||
| 140 | */ | ||
| 141 | showSpinner() { | ||
| 142 | const spinner = this.container.querySelector('.dataMaidSpinner'); | ||
| 143 | const placeholder = this.container.querySelector('.dataMaidPlaceholder'); | ||
| 144 | placeholder.classList.add('displayNone'); | ||
| 145 | spinner.classList.remove('displayNone'); | ||
| 146 | } | ||
| 147 | |||
| 148 | /** | ||
| 149 | * Hides the loading spinner. | ||
| 150 | * @private | ||
| 151 | */ | ||
| 152 | hideSpinner() { | ||
| 153 | const spinner = this.container.querySelector('.dataMaidSpinner'); | ||
| 154 | spinner.classList.add('displayNone'); | ||
| 155 | } | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Renders the Data Maid report into the results list. | ||
| 159 | * @param {DataMaidReportResult} report | ||
| 160 | * @param {Element} resultsList | ||
| 161 | * @private | ||
| 162 | */ | ||
| 163 | async renderReport(report, resultsList) { | ||
| 164 | for (const [prop, data] of Object.entries(this.DATA_MAID_CATEGORIES)) { | ||
| 165 | const category = await this.renderCategory(prop, data.name, data.description, report.report[prop]); | ||
| 166 | if (!category) { | ||
| 167 | continue; | ||
| 168 | } | ||
| 169 | resultsList.appendChild(category); | ||
| 170 | } | ||
| 171 | this.displayEmptyPlaceholder(); | ||
| 172 | } | ||
| 173 | |||
| 174 | /** | ||
| 175 | * Displays a placeholder message if no items are found in the results list. | ||
| 176 | * @private | ||
| 177 | */ | ||
| 178 | displayEmptyPlaceholder() { | ||
| 179 | const resultsList = this.container.querySelector('.dataMaidResultsList'); | ||
| 180 | if (resultsList.children.length === 0) { | ||
| 181 | const placeholder = this.container.querySelector('.dataMaidPlaceholder'); | ||
| 182 | placeholder.classList.remove('displayNone'); | ||
| 183 | placeholder.textContent = t`No items found to clean up. Come back later!`; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | /** | ||
| 188 | * Renders a single Data Maid category into a DOM element. | ||
| 189 | * @param {string} prop Property name for the category | ||
| 190 | * @param {string} name Name of the category | ||
| 191 | * @param {string} description Description of the category | ||
| 192 | * @param {import('../../src/endpoints/data-maid.js').DataMaidSanitizedRecord[]} items List of items in the category | ||
| 193 | * @return {Promise<Element|null>} A promise that resolves to a DOM element containing the rendered category | ||
| 194 | * @private | ||
| 195 | */ | ||
| 196 | async renderCategory(prop, name, description, items) { | ||
| 197 | if (!Array.isArray(items) || items.length === 0) { | ||
| 198 | return null; | ||
| 199 | } | ||
| 200 | |||
| 201 | const viewModel = { | ||
| 202 | name: name, | ||
| 203 | description: description, | ||
| 204 | totalSize: humanFileSize(items.reduce((sum, item) => sum + item.size, 0)), | ||
| 205 | totalItems: items.length, | ||
| 206 | items: items.sort((a, b) => b.mtime - a.mtime).map(item => ({ | ||
| 207 | ...item, | ||
| 208 | size: humanFileSize(item.size), | ||
| 209 | date: timestampToMoment(item.mtime).format('L LT'), | ||
| 210 | })), | ||
| 211 | }; | ||
| 212 | |||
| 213 | const template = await renderTemplateAsync('dataMaidCategory', viewModel); | ||
| 214 | const categoryElement = document.createElement('div'); | ||
| 215 | categoryElement.innerHTML = template; | ||
| 216 | categoryElement.querySelectorAll('.dataMaidItemView').forEach(button => { | ||
| 217 | button.addEventListener('click', async () => { | ||
| 218 | const item = button.closest('.dataMaidItem'); | ||
| 219 | const hash = item?.getAttribute('data-hash'); | ||
| 220 | if (hash) { | ||
| 221 | await this.view(prop, hash); | ||
| 222 | } | ||
| 223 | }); | ||
| 224 | }); | ||
| 225 | categoryElement.querySelectorAll('.dataMaidItemDownload').forEach(button => { | ||
| 226 | button.addEventListener('click', async () => { | ||
| 227 | const item = button.closest('.dataMaidItem'); | ||
| 228 | const hash = item?.getAttribute('data-hash'); | ||
| 229 | if (hash) { | ||
| 230 | await this.download(items, hash); | ||
| 231 | } | ||
| 232 | }); | ||
| 233 | }); | ||
| 234 | categoryElement.querySelectorAll('.dataMaidDeleteAll').forEach(button => { | ||
| 235 | button.addEventListener('click', async (event) => { | ||
| 236 | event.stopPropagation(); | ||
| 237 | const confirm = await Popup.show.confirm(t`Are you sure?`, t`This will permanently delete all files in this category. THIS CANNOT BE UNDONE!`); | ||
| 238 | if (!confirm) { | ||
| 239 | return; | ||
| 240 | } | ||
| 241 | |||
| 242 | const hashes = items.map(item => item.hash).filter(hash => hash); | ||
| 243 | await this.delete(hashes); | ||
| 244 | |||
| 245 | categoryElement.remove(); | ||
| 246 | this.displayEmptyPlaceholder(); | ||
| 247 | }); | ||
| 248 | |||
| 249 | }); | ||
| 250 | categoryElement.querySelectorAll('.dataMaidItemDelete').forEach(button => { | ||
| 251 | button.addEventListener('click', async () => { | ||
| 252 | const item = button.closest('.dataMaidItem'); | ||
| 253 | const hash = item?.getAttribute('data-hash'); | ||
| 254 | if (hash) { | ||
| 255 | const confirm = await Popup.show.confirm(t`Are you sure?`, t`This will permanently delete the file. THIS CANNOT BE UNDONE!`); | ||
| 256 | if (!confirm) { | ||
| 257 | return; | ||
| 258 | } | ||
| 259 | if (await this.delete([hash])) { | ||
| 260 | item.remove(); | ||
| 261 | items.splice(items.findIndex(i => i.hash === hash), 1); | ||
| 262 | if (items.length === 0) { | ||
| 263 | categoryElement.remove(); | ||
| 264 | this.displayEmptyPlaceholder(); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | } | ||
| 268 | }); | ||
| 269 | }); | ||
| 270 | return categoryElement; | ||
| 271 | } | ||
| 272 | |||
| 273 | /** | ||
| 274 | * Constructs the URL for viewing an item by its hash. | ||
| 275 | * @param {string} hash Hash of the item to view | ||
| 276 | * @returns {string} URL to view the item | ||
| 277 | * @private | ||
| 278 | */ | ||
| 279 | getViewUrl(hash) { | ||
| 280 | return `/api/data-maid/view?hash=${encodeURIComponent(hash)}&token=${encodeURIComponent(this.token)}`; | ||
| 281 | } | ||
| 282 | |||
| 283 | /** | ||
| 284 | * Downloads an item by its hash. | ||
| 285 | * @param {import('../../src/endpoints/data-maid.js').DataMaidSanitizedRecord[]} items List of items in the category | ||
| 286 | * @param {string} hash Hash of the item to download | ||
| 287 | * @private | ||
| 288 | */ | ||
| 289 | async download(items, hash) { | ||
| 290 | const item = items.find(i => i.hash === hash); | ||
| 291 | if (!item) { | ||
| 292 | return; | ||
| 293 | } | ||
| 294 | const url = this.getViewUrl(hash); | ||
| 295 | const a = document.createElement('a'); | ||
| 296 | a.href = url; | ||
| 297 | a.download = item?.name || hash; | ||
| 298 | document.body.appendChild(a); | ||
| 299 | a.click(); | ||
| 300 | document.body.removeChild(a); | ||
| 301 | } | ||
| 302 | |||
| 303 | /** | ||
| 304 | * Opens the item view for a specific hash. | ||
| 305 | * @param {string} prop Property name for the category | ||
| 306 | * @param {string} hash Item hash to view | ||
| 307 | * @private | ||
| 308 | */ | ||
| 309 | async view(prop, hash) { | ||
| 310 | const url = this.getViewUrl(hash); | ||
| 311 | const isImage = ['images', 'avatarThumbnails', 'backgroundThumbnails'].includes(prop); | ||
| 312 | const element = isImage | ||
| 313 | ? await this.getViewElement(url) | ||
| 314 | : await this.getTextViewElement(url); | ||
| 315 | await callGenericPopup(element, POPUP_TYPE.DISPLAY, '', { large: true, wide: true }); | ||
| 316 | } | ||
| 317 | |||
| 318 | /** | ||
| 319 | * Deletes an item by its file path hash. | ||
| 320 | * @param {string[]} hashes Hashes of items to delete | ||
| 321 | * @return {Promise<boolean>} True if the deletion was successful, false otherwise | ||
| 322 | * @private | ||
| 323 | */ | ||
| 324 | async delete(hashes) { | ||
| 325 | try { | ||
| 326 | const response = await fetch('/api/data-maid/delete', { | ||
| 327 | method: 'POST', | ||
| 328 | headers: getRequestHeaders(), | ||
| 329 | body: JSON.stringify({ hashes: hashes, token: this.token }), | ||
| 330 | }); | ||
| 331 | |||
| 332 | if (!response.ok) { | ||
| 333 | throw new Error(`Error deleting item: ${response.statusText}`); | ||
| 334 | } | ||
| 335 | |||
| 336 | return true; | ||
| 337 | } catch (error) { | ||
| 338 | console.error('Error deleting item:', error); | ||
| 339 | return false; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | /** | ||
| 344 | * Gets an image element for viewing images. | ||
| 345 | * @param {string} url View URL | ||
| 346 | * @returns {Promise<HTMLElement>} Image element | ||
| 347 | * @private | ||
| 348 | */ | ||
| 349 | async getViewElement(url) { | ||
| 350 | const img = document.createElement('img'); | ||
| 351 | img.src = url; | ||
| 352 | img.classList.add('dataMaidImageView'); | ||
| 353 | return img; | ||
| 354 | } | ||
| 355 | |||
| 356 | /** | ||
| 357 | * Gets an iframe element for viewing text content. | ||
| 358 | * @param {string} url View URL | ||
| 359 | * @returns {Promise<HTMLTextAreaElement>} Frame element | ||
| 360 | * @private | ||
| 361 | */ | ||
| 362 | async getTextViewElement(url) { | ||
| 363 | const response = await fetch(url); | ||
| 364 | const text = await response.text(); | ||
| 365 | const element = document.createElement('textarea'); | ||
| 366 | element.classList.add('dataMaidTextView'); | ||
| 367 | element.readOnly = true; | ||
| 368 | element.textContent = text; | ||
| 369 | return element; | ||
| 370 | } | ||
| 371 | |||
| 372 | /** | ||
| 373 | * Opens the Data Maid dialog and handles the interaction. | ||
| 374 | */ | ||
| 375 | async open() { | ||
| 376 | await this.setupDialogUI(); | ||
| 377 | await callGenericPopup(this.container, POPUP_TYPE.TEXT, '', { wide: true, large: true }); | ||
| 378 | |||
| 379 | if (this.token) { | ||
| 380 | await this.finalize(); | ||
| 381 | } | ||
| 382 | } | ||
| 383 | } | ||
| 384 | |||
| 385 | export function initDataMaid() { | ||
| 386 | const dataMaidButton = document.getElementById('data_maid_button'); | ||
| 387 | if (!dataMaidButton) { | ||
| 388 | console.warn('Data Maid button not found'); | ||
| 389 | return; | ||
| 390 | } | ||
| 391 | |||
| 392 | dataMaidButton.addEventListener('click', () => new DataMaidDialog().open()); | ||
| 393 | } | ||
| @@ -36,7 +36,13 @@ export let modules = []; | |||
| 36 | * A set of active extensions. | 36 | * A set of active extensions. |
| 37 | * @type {Set<string>} | 37 | * @type {Set<string>} |
| 38 | */ | 38 | */ |
| 39 | let activeExtensions = new Set(); | 39 | const activeExtensions = new Set(); |
| 40 | |||
| 41 | /** | ||
| 42 | * Errors that occurred while loading extensions. | ||
| 43 | * @type {Set<string>} | ||
| 44 | */ | ||
| 45 | const extensionLoadErrors = new Set(); | ||
| 40 | 46 | ||
| 41 | const getApiUrl = () => extension_settings.apiUrl; | 47 | const getApiUrl = () => extension_settings.apiUrl; |
| 42 | const sortManifestsByOrder = (a, b) => parseInt(a.loading_order) - parseInt(b.loading_order) || String(a.display_name).localeCompare(String(b.display_name)); | 48 | const sortManifestsByOrder = (a, b) => parseInt(a.loading_order) - parseInt(b.loading_order) || String(a.display_name).localeCompare(String(b.display_name)); |
| @@ -172,6 +178,7 @@ export const extension_settings = { | |||
| 172 | llmPrompt: undefined, | 178 | llmPrompt: undefined, |
| 173 | allowMultiple: true, | 179 | allowMultiple: true, |
| 174 | rerollIfSame: false, | 180 | rerollIfSame: false, |
| 181 | promptType: 'raw', | ||
| 175 | }, | 182 | }, |
| 176 | connectionManager: { | 183 | connectionManager: { |
| 177 | selectedProfile: '', | 184 | selectedProfile: '', |
| @@ -379,37 +386,90 @@ async function getManifests(names) { | |||
| 379 | * @returns {Promise<void>} | 386 | * @returns {Promise<void>} |
| 380 | */ | 387 | */ |
| 381 | async function activateExtensions() { | 388 | async function activateExtensions() { |
| 389 | extensionLoadErrors.clear(); | ||
| 382 | const extensions = Object.entries(manifests).sort((a, b) => sortManifestsByOrder(a[1], b[1])); | 390 | const extensions = Object.entries(manifests).sort((a, b) => sortManifestsByOrder(a[1], b[1])); |
| 391 | const extensionNames = extensions.map(x => x[0]); | ||
| 383 | const promises = []; | 392 | const promises = []; |
| 384 | 393 | ||
| 385 | for (let entry of extensions) { | 394 | for (let entry of extensions) { |
| 386 | const name = entry[0]; | 395 | const name = entry[0]; |
| 387 | const manifest = entry[1]; | 396 | const manifest = entry[1]; |
| 397 | const extrasRequirements = manifest.requires; | ||
| 398 | const extensionDependencies = manifest.dependencies; | ||
| 399 | const displayName = manifest.display_name || name; | ||
| 388 | 400 | ||
| 389 | if (activeExtensions.has(name)) { | 401 | if (activeExtensions.has(name)) { |
| 390 | continue; | 402 | continue; |
| 391 | } | 403 | } |
| 392 | 404 | ||
| 393 | const meetsModuleRequirements = !Array.isArray(manifest.requires) || isSubsetOf(modules, manifest.requires); | 405 | // Module requirements: pass if 'requires' is undefined, null, or not an array; check subset if it's an array |
| 406 | let meetsModuleRequirements = true; | ||
| 407 | let missingModules = []; | ||
| 408 | if (extrasRequirements !== undefined) { | ||
| 409 | if (Array.isArray(extrasRequirements)) { | ||
| 410 | meetsModuleRequirements = isSubsetOf(modules, extrasRequirements); | ||
| 411 | missingModules = extrasRequirements.filter(req => !modules.includes(req)); | ||
| 412 | } else { | ||
| 413 | console.warn(`Extension ${name}: manifest.json 'requires' field is not an array. Loading allowed, but any intended requirements were not verified to exist.`); | ||
| 414 | } | ||
| 415 | } | ||
| 416 | |||
| 417 | // Extension dependencies: pass if 'dependencies' is undefined or not an array; check subset and disabled status if it's an array | ||
| 418 | let meetsExtensionDeps = true; | ||
| 419 | let missingDependencies = []; | ||
| 420 | let disabledDependencies = []; | ||
| 421 | if (extensionDependencies !== undefined) { | ||
| 422 | if (Array.isArray(extensionDependencies)) { | ||
| 423 | // Check if all dependencies exist | ||
| 424 | meetsExtensionDeps = isSubsetOf(extensionNames, extensionDependencies); | ||
| 425 | missingDependencies = extensionDependencies.filter(dep => !extensionNames.includes(dep)); | ||
| 426 | // Check for disabled dependencies | ||
| 427 | if (meetsExtensionDeps) { | ||
| 428 | disabledDependencies = extensionDependencies.filter(dep => extension_settings.disabledExtensions.includes(dep)); | ||
| 429 | if (disabledDependencies.length > 0) { | ||
| 430 | // Fail if any dependencies are disabled | ||
| 431 | meetsExtensionDeps = false; | ||
| 432 | } | ||
| 433 | } | ||
| 434 | } else { | ||
| 435 | console.warn(`Extension ${name}: manifest.json 'dependencies' field is not an array. Loading allowed, but any intended requirements were not verified to exist.`); | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 394 | const isDisabled = extension_settings.disabledExtensions.includes(name); | 439 | const isDisabled = extension_settings.disabledExtensions.includes(name); |
| 395 | 440 | ||
| 396 | if (meetsModuleRequirements && !isDisabled) { | 441 | if (meetsModuleRequirements && meetsExtensionDeps && !isDisabled) { |
| 397 | try { | 442 | try { |
| 398 | console.debug('Activating extension', name); | 443 | console.debug('Activating extension', name); |
| 399 | const promise = addExtensionLocale(name, manifest).finally(() => Promise.all([addExtensionScript(name, manifest), addExtensionStyle(name, manifest)])); | 444 | const promise = addExtensionLocale(name, manifest).finally(() => |
| 445 | Promise.all([addExtensionScript(name, manifest), addExtensionStyle(name, manifest)]), | ||
| 446 | ); | ||
| 400 | await promise | 447 | await promise |
| 401 | .then(() => activeExtensions.add(name)) | 448 | .then(() => activeExtensions.add(name)) |
| 402 | .catch(err => console.log('Could not activate extension', name, err)); | 449 | .catch(err => { |
| 450 | console.log('Could not activate extension', name, err); | ||
| 451 | extensionLoadErrors.add(t`Extension "${displayName}" failed to load: ${err}`); | ||
| 452 | }); | ||
| 403 | promises.push(promise); | 453 | promises.push(promise); |
| 454 | } catch (error) { | ||
| 455 | console.error('Could not activate extension', name, error); | ||
| 404 | } | 456 | } |
| 405 | catch (error) { | 457 | } else if (!meetsModuleRequirements && !isDisabled) { |
| 406 | console.error('Could not activate extension', name); | 458 | console.warn(t`Extension "${name}" did not load. Missing required Extras module(s): "${missingModules.join(', ')}"`); |
| 407 | console.error(error); | 459 | extensionLoadErrors.add(t`Extension "${displayName}" did not load. Missing required Extras module(s): "${missingModules.join(', ')}"`); |
| 460 | } else if (!meetsExtensionDeps && !isDisabled) { | ||
| 461 | if (disabledDependencies.length > 0) { | ||
| 462 | console.warn(t`Extension "${name}" did not load. Required extensions exist but are disabled: "${disabledDependencies.join(', ')}". Enable them first, then reload.`); | ||
| 463 | extensionLoadErrors.add(t`Extension "${displayName}" did not load. Required extensions exist but are disabled: "${disabledDependencies.join(', ')}". Enable them first, then reload.`); | ||
| 464 | } else { | ||
| 465 | console.warn(t`Extension "${name}" did not load. Missing required extensions: "${missingDependencies.join(', ')}"`); | ||
| 466 | extensionLoadErrors.add(t`Extension "${displayName}" did not load. Missing required extensions: "${missingDependencies.join(', ')}"`); | ||
| 408 | } | 467 | } |
| 409 | } | 468 | } |
| 410 | } | 469 | } |
| 411 | 470 | ||
| 412 | await Promise.allSettled(promises); | 471 | await Promise.allSettled(promises); |
| 472 | $('#extensions_details').toggleClass('warning', extensionLoadErrors.size > 0); | ||
| 413 | } | 473 | } |
| 414 | 474 | ||
| 415 | async function connectClickHandler() { | 475 | async function connectClickHandler() { |
| @@ -752,6 +812,27 @@ function getModuleInformation() { | |||
| 752 | } | 812 | } |
| 753 | 813 | ||
| 754 | /** | 814 | /** |
| 815 | * Generates HTML for the extension load errors. | ||
| 816 | * @returns {string} HTML string containing the errors that occurred while loading extensions. | ||
| 817 | */ | ||
| 818 | function getExtensionLoadErrorsHtml() { | ||
| 819 | if (extensionLoadErrors.size === 0) { | ||
| 820 | return ''; | ||
| 821 | } | ||
| 822 | |||
| 823 | const container = document.createElement('div'); | ||
| 824 | container.classList.add('info-block', 'error'); | ||
| 825 | |||
| 826 | for (const error of extensionLoadErrors) { | ||
| 827 | const errorElement = document.createElement('div'); | ||
| 828 | errorElement.textContent = error; | ||
| 829 | container.appendChild(errorElement); | ||
| 830 | } | ||
| 831 | |||
| 832 | return container.outerHTML; | ||
| 833 | } | ||
| 834 | |||
| 835 | /** | ||
| 755 | * Generates the HTML strings for all extensions and displays them in a popup. | 836 | * Generates the HTML strings for all extensions and displays them in a popup. |
| 756 | */ | 837 | */ |
| 757 | async function showExtensionsDetails() { | 838 | async function showExtensionsDetails() { |
| @@ -765,6 +846,7 @@ async function showExtensionsDetails() { | |||
| 765 | initialScrollTop = oldPopup.content.scrollTop; | 846 | initialScrollTop = oldPopup.content.scrollTop; |
| 766 | await oldPopup.completeCancelled(); | 847 | await oldPopup.completeCancelled(); |
| 767 | } | 848 | } |
| 849 | const htmlErrors = getExtensionLoadErrorsHtml(); | ||
| 768 | const htmlDefault = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Built-in Extensions:` + '</h3></div>'); | 850 | const htmlDefault = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Built-in Extensions:` + '</h3></div>'); |
| 769 | const htmlExternal = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Installed Extensions:` + '</h3></div>'); | 851 | const htmlExternal = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Installed Extensions:` + '</h3></div>'); |
| 770 | const htmlLoading = $(`<div class="flex-container alignItemsCenter justifyCenter marginTop10 marginBot5"> | 852 | const htmlLoading = $(`<div class="flex-container alignItemsCenter justifyCenter marginTop10 marginBot5"> |
| @@ -787,6 +869,7 @@ async function showExtensionsDetails() { | |||
| 787 | 869 | ||
| 788 | const html = $('<div></div>') | 870 | const html = $('<div></div>') |
| 789 | .addClass('extensions_info') | 871 | .addClass('extensions_info') |
| 872 | .append(htmlErrors) | ||
| 790 | .append(htmlDefault) | 873 | .append(htmlDefault) |
| 791 | .append(htmlExternal) | 874 | .append(htmlExternal) |
| 792 | .append(getModuleInformation()); | 875 | .append(getModuleInformation()); |
| @@ -893,11 +976,14 @@ async function onUpdateClick() { | |||
| 893 | * Updates a third-party extension via the API. | 976 | * Updates a third-party extension via the API. |
| 894 | * @param {string} extensionName Extension folder name | 977 | * @param {string} extensionName Extension folder name |
| 895 | * @param {boolean} quiet If true, don't show a success message | 978 | * @param {boolean} quiet If true, don't show a success message |
| 979 | * @param {number?} timeout Timeout in milliseconds to wait for the update to complete. If null, no timeout is set. | ||
| 896 | */ | 980 | */ |
| 897 | async function updateExtension(extensionName, quiet) { | 981 | async function updateExtension(extensionName, quiet, timeout = null) { |
| 898 | try { | 982 | try { |
| 983 | const signal = timeout ? AbortSignal.timeout(timeout) : undefined; | ||
| 899 | const response = await fetch('/api/extensions/update', { | 984 | const response = await fetch('/api/extensions/update', { |
| 900 | method: 'POST', | 985 | method: 'POST', |
| 986 | signal: signal, | ||
| 901 | headers: getRequestHeaders(), | 987 | headers: getRequestHeaders(), |
| 902 | body: JSON.stringify({ | 988 | body: JSON.stringify({ |
| 903 | extensionName, | 989 | extensionName, |
| @@ -926,7 +1012,7 @@ async function updateExtension(extensionName, quiet) { | |||
| 926 | toastr.success(t`Extension ${extensionName} updated to ${data.shortCommitHash}`, t`Reload the page to apply updates`); | 1012 | toastr.success(t`Extension ${extensionName} updated to ${data.shortCommitHash}`, t`Reload the page to apply updates`); |
| 927 | } | 1013 | } |
| 928 | } catch (error) { | 1014 | } catch (error) { |
| 929 | console.error('Error:', error); | 1015 | console.error('Extension update error:', error); |
| 930 | } | 1016 | } |
| 931 | } | 1017 | } |
| 932 | 1018 | ||
| @@ -1397,6 +1483,7 @@ async function autoUpdateExtensions(forceAll) { | |||
| 1397 | const banner = toastr.info(t`Auto-updating extensions. This may take several minutes.`, t`Please wait...`, { timeOut: 10000, extendedTimeOut: 10000 }); | 1483 | const banner = toastr.info(t`Auto-updating extensions. This may take several minutes.`, t`Please wait...`, { timeOut: 10000, extendedTimeOut: 10000 }); |
| 1398 | const isCurrentUserAdmin = isAdmin(); | 1484 | const isCurrentUserAdmin = isAdmin(); |
| 1399 | const promises = []; | 1485 | const promises = []; |
| 1486 | const autoUpdateTimeout = 60 * 1000; | ||
| 1400 | for (const [id, manifest] of Object.entries(manifests)) { | 1487 | for (const [id, manifest] of Object.entries(manifests)) { |
| 1401 | const isDisabled = extension_settings.disabledExtensions.includes(id); | 1488 | const isDisabled = extension_settings.disabledExtensions.includes(id); |
| 1402 | if (!forceAll && isDisabled) { | 1489 | if (!forceAll && isDisabled) { |
| @@ -1410,7 +1497,7 @@ async function autoUpdateExtensions(forceAll) { | |||
| 1410 | } | 1497 | } |
| 1411 | if ((forceAll || manifest.auto_update) && id.startsWith('third-party')) { | 1498 | if ((forceAll || manifest.auto_update) && id.startsWith('third-party')) { |
| 1412 | console.debug(`Auto-updating 3rd-party extension: ${manifest.display_name} (${id})`); | 1499 | console.debug(`Auto-updating 3rd-party extension: ${manifest.display_name} (${id})`); |
| 1413 | promises.push(updateExtension(id.replace('third-party', ''), true)); | 1500 | promises.push(updateExtension(id.replace('third-party', ''), true, autoUpdateTimeout)); |
| 1414 | } | 1501 | } |
| 1415 | } | 1502 | } |
| 1416 | await Promise.allSettled(promises); | 1503 | await Promise.allSettled(promises); |
| @@ -1453,7 +1540,7 @@ export async function runGenerationInterceptors(chat, contextSize, type) { | |||
| 1453 | 1540 | ||
| 1454 | /** | 1541 | /** |
| 1455 | * Writes a field to the character's data extensions object. | 1542 | * Writes a field to the character's data extensions object. |
| 1456 | * @param {number} characterId Index in the character array | 1543 | * @param {number|string} characterId Index in the character array |
| 1457 | * @param {string} key Field name | 1544 | * @param {string} key Field name |
| 1458 | * @param {any} value Field value | 1545 | * @param {any} value Field value |
| 1459 | * @returns {Promise<void>} When the field is written | 1546 | * @returns {Promise<void>} When the field is written |
| @@ -53,11 +53,11 @@ function filterAssets() { | |||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | const KNOWN_TYPES = { | 55 | const KNOWN_TYPES = { |
| 56 | 'extension': 'Extensions', | 56 | 'extension': t`Extensions`, |
| 57 | 'character': 'Characters', | 57 | 'character': t`Characters`, |
| 58 | 'ambient': 'Ambient sounds', | 58 | 'ambient': t`Ambient sounds`, |
| 59 | 'bgm': 'Background music', | 59 | 'bgm': t`Background music`, |
| 60 | 'blip': 'Blip sounds', | 60 | 'blip': t`Blip sounds`, |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | async function downloadAssetsList(url) { | 63 | async function downloadAssetsList(url) { |
| @@ -65,7 +65,7 @@ | |||
| 65 | .asset-download-button-text { | 65 | .asset-download-button-text { |
| 66 | font: bold 20px "Quicksand", san-serif; | 66 | font: bold 20px "Quicksand", san-serif; |
| 67 | color: #ffffff; | 67 | color: #ffffff; |
| 68 | transition: all 0.2s; | 68 | transition: all var(--animation-duration-2x); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | .asset-download-button-loading .asset-download-button-text { | 71 | .asset-download-button-loading .asset-download-button-text { |
| @@ -216,8 +216,37 @@ function cleanUpAttachments() { | |||
| 216 | } | 216 | } |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | /** | ||
| 220 | * Clean up character attachments when a character is deleted. | ||
| 221 | * @param {{character: import('../../char-data.js').v1CharData}} data Event data | ||
| 222 | */ | ||
| 223 | function cleanUpCharacterAttachments(data) { | ||
| 224 | const avatar = data?.character?.avatar; | ||
| 225 | if (!avatar) return; | ||
| 226 | if (Array.isArray(extension_settings?.character_attachments?.[avatar])) { | ||
| 227 | delete extension_settings.character_attachments[avatar]; | ||
| 228 | saveSettingsDebounced(); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | /** | ||
| 233 | * Handle character rename event to update character attachments. | ||
| 234 | * @param {string} oldAvatar Old avatar name | ||
| 235 | * @param {string} newAvatar New avatar name | ||
| 236 | */ | ||
| 237 | function handleCharacterRename(oldAvatar, newAvatar) { | ||
| 238 | if (!oldAvatar || !newAvatar) return; | ||
| 239 | if (Array.isArray(extension_settings?.character_attachments?.[oldAvatar])) { | ||
| 240 | extension_settings.character_attachments[newAvatar] = extension_settings.character_attachments[oldAvatar]; | ||
| 241 | delete extension_settings.character_attachments[oldAvatar]; | ||
| 242 | saveSettingsDebounced(); | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 219 | jQuery(async () => { | 246 | jQuery(async () => { |
| 220 | eventSource.on(event_types.APP_READY, cleanUpAttachments); | 247 | eventSource.on(event_types.APP_READY, cleanUpAttachments); |
| 248 | eventSource.on(event_types.CHARACTER_DELETED, cleanUpCharacterAttachments); | ||
| 249 | eventSource.on(event_types.CHARACTER_RENAMED, handleCharacterRename); | ||
| 221 | const manageButton = await renderExtensionTemplateAsync('attachments', 'manage-button', {}); | 250 | const manageButton = await renderExtensionTemplateAsync('attachments', 'manage-button', {}); |
| 222 | const attachButton = await renderExtensionTemplateAsync('attachments', 'attach-button', {}); | 251 | const attachButton = await renderExtensionTemplateAsync('attachments', 'attach-button', {}); |
| 223 | $('#data_bank_wand_container').append(manageButton); | 252 | $('#data_bank_wand_container').append(manageButton); |
| @@ -3,7 +3,7 @@ | |||
| 3 | File Name | 3 | File Name |
| 4 | </label> | 4 | </label> |
| 5 | <input type="text" class="text_pole" id="notepadFileName" name="notepadFileName" value="" /> | 5 | <input type="text" class="text_pole" id="notepadFileName" name="notepadFileName" value="" /> |
| 6 | <labels> | 6 | <label> |
| 7 | File Content | 7 | File Content |
| 8 | </label> | 8 | </label> |
| 9 | <textarea id="notepadFileContent" name="notepadFileContent" class="text_pole textarea_compact monospace flex1" placeholder="Enter your notes here."></textarea> | 9 | <textarea id="notepadFileContent" name="notepadFileContent" class="text_pole textarea_compact monospace flex1" placeholder="Enter your notes here."></textarea> |
| @@ -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, eventSource, event_types, getRequestHeaders, 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'; |
| @@ -9,6 +9,7 @@ import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js'; | |||
| 9 | import { SlashCommand } from '../../slash-commands/SlashCommand.js'; | 9 | import { SlashCommand } from '../../slash-commands/SlashCommand.js'; |
| 10 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js'; | 10 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js'; |
| 11 | import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; | 11 | import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 12 | import { callGenericPopup, Popup, POPUP_TYPE } from '../../popup.js'; | ||
| 12 | export { MODULE_NAME }; | 13 | export { MODULE_NAME }; |
| 13 | 14 | ||
| 14 | const MODULE_NAME = 'caption'; | 15 | const MODULE_NAME = 'caption'; |
| @@ -98,9 +99,9 @@ async function wrapCaptionTemplate(caption) { | |||
| 98 | let messageText = substituteParamsExtended(template, { caption: caption }); | 99 | let messageText = substituteParamsExtended(template, { caption: caption }); |
| 99 | 100 | ||
| 100 | if (extension_settings.caption.refine_mode) { | 101 | if (extension_settings.caption.refine_mode) { |
| 101 | messageText = await callPopup( | 102 | messageText = await Popup.show.input( |
| 102 | '<h3>Review and edit the generated caption:</h3>Press "Cancel" to abort the caption sending.', | 103 | 'Review and edit the generated caption:', |
| 103 | 'input', | 104 | 'Press "Cancel" to abort the caption sending.', |
| 104 | messageText, | 105 | messageText, |
| 105 | { rows: 5, okButton: 'Send' }); | 106 | { rows: 5, okButton: 'Send' }); |
| 106 | 107 | ||
| @@ -278,7 +279,7 @@ async function captionMultimodal(base64Img, externalPrompt) { | |||
| 278 | let prompt = externalPrompt || extension_settings.caption.prompt || PROMPT_DEFAULT; | 279 | let prompt = externalPrompt || extension_settings.caption.prompt || PROMPT_DEFAULT; |
| 279 | 280 | ||
| 280 | if (!externalPrompt && extension_settings.caption.prompt_ask) { | 281 | if (!externalPrompt && extension_settings.caption.prompt_ask) { |
| 281 | const customPrompt = await callPopup('<h3>Enter a comment or question:</h3>', 'input', prompt, { rows: 2 }); | 282 | const customPrompt = await callGenericPopup('Enter a comment or question:', POPUP_TYPE.INPUT, prompt, { rows: 2 }); |
| 282 | if (!customPrompt) { | 283 | if (!customPrompt) { |
| 283 | throw new Error('User aborted the caption sending.'); | 284 | throw new Error('User aborted the caption sending.'); |
| 284 | } | 285 | } |
| @@ -432,6 +433,7 @@ jQuery(async function () { | |||
| 432 | 'zerooneai': SECRET_KEYS.ZEROONEAI, | 433 | 'zerooneai': SECRET_KEYS.ZEROONEAI, |
| 433 | 'groq': SECRET_KEYS.GROQ, | 434 | 'groq': SECRET_KEYS.GROQ, |
| 434 | 'cohere': SECRET_KEYS.COHERE, | 435 | 'cohere': SECRET_KEYS.COHERE, |
| 436 | 'aimlapi': SECRET_KEYS.AIMLAPI, | ||
| 435 | }; | 437 | }; |
| 436 | 438 | ||
| 437 | if (chatCompletionApis[api] && secret_state[chatCompletionApis[api]]) { | 439 | if (chatCompletionApis[api] && secret_state[chatCompletionApis[api]]) { |
| @@ -18,6 +18,7 @@ | |||
| 18 | <label for="caption_multimodal_api" data-i18n="API">API</label> | 18 | <label for="caption_multimodal_api" data-i18n="API">API</label> |
| 19 | <select id="caption_multimodal_api" class="flex1 text_pole"> | 19 | <select id="caption_multimodal_api" class="flex1 text_pole"> |
| 20 | <option value="zerooneai">01.AI (Yi)</option> | 20 | <option value="zerooneai">01.AI (Yi)</option> |
| 21 | <option value="aimlapi">AI/ML API</option> | ||
| 21 | <option value="anthropic">Anthropic</option> | 22 | <option value="anthropic">Anthropic</option> |
| 22 | <option value="cohere">Cohere</option> | 23 | <option value="cohere">Cohere</option> |
| 23 | <option value="custom" data-i18n="Custom (OpenAI-compatible)">Custom (OpenAI-compatible)</option> | 24 | <option value="custom" data-i18n="Custom (OpenAI-compatible)">Custom (OpenAI-compatible)</option> |
| @@ -85,11 +86,15 @@ | |||
| 85 | <option data-type="anthropic" value="claude-3-opus-20240229">claude-3-opus-20240229</option> | 86 | <option data-type="anthropic" value="claude-3-opus-20240229">claude-3-opus-20240229</option> |
| 86 | <option data-type="anthropic" value="claude-3-sonnet-20240229">claude-3-sonnet-20240229</option> | 87 | <option data-type="anthropic" value="claude-3-sonnet-20240229">claude-3-sonnet-20240229</option> |
| 87 | <option data-type="anthropic" value="claude-3-haiku-20240307">claude-3-haiku-20240307</option> | 88 | <option data-type="anthropic" value="claude-3-haiku-20240307">claude-3-haiku-20240307</option> |
| 89 | <option data-type="google" value="gemini-2.5-pro">gemini-2.5-pro</option> | ||
| 90 | <option data-type="google" value="gemini-2.5-pro-preview-06-05">gemini-2.5-pro-preview-06-05</option> | ||
| 88 | <option data-type="google" value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> | 91 | <option data-type="google" value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> |
| 89 | <option data-type="google" value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> | 92 | <option data-type="google" value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> |
| 90 | <option data-type="google" value="gemini-2.5-pro-exp-03-25">gemini-2.5-pro-exp-03-25</option> | 93 | <option data-type="google" value="gemini-2.5-pro-exp-03-25">gemini-2.5-pro-exp-03-25</option> |
| 94 | <option data-type="google" value="gemini-2.5-flash">gemini-2.5-flash</option> | ||
| 91 | <option data-type="google" value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> | 95 | <option data-type="google" value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> |
| 92 | <option data-type="google" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | 96 | <option data-type="google" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> |
| 97 | <option data-type="google" value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> | ||
| 93 | <option data-type="google" value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05 → 2.5-pro-exp-03-25</option> | 98 | <option data-type="google" value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05 → 2.5-pro-exp-03-25</option> |
| 94 | <option data-type="google" value="gemini-2.0-pro-exp">gemini-2.0-pro-exp → 2.5-pro-exp-03-25</option> | 99 | <option data-type="google" value="gemini-2.0-pro-exp">gemini-2.0-pro-exp → 2.5-pro-exp-03-25</option> |
| 95 | <option data-type="google" value="gemini-exp-1206">gemini-exp-1206 → 2.5-pro-exp-03-25</option> | 100 | <option data-type="google" value="gemini-exp-1206">gemini-exp-1206 → 2.5-pro-exp-03-25</option> |
| @@ -116,15 +121,37 @@ | |||
| 116 | <option data-type="google" value="gemini-1.5-flash-8b-exp-0827">gemini-1.5-flash-8b-exp-0827</option> | 121 | <option data-type="google" value="gemini-1.5-flash-8b-exp-0827">gemini-1.5-flash-8b-exp-0827</option> |
| 117 | <option data-type="google" value="learnlm-2.0-flash-experimental">learnlm-2.0-flash-experimental</option> | 122 | <option data-type="google" value="learnlm-2.0-flash-experimental">learnlm-2.0-flash-experimental</option> |
| 118 | <option data-type="google" value="learnlm-1.5-pro-experimental">learnlm-1.5-pro-experimental</option> | 123 | <option data-type="google" value="learnlm-1.5-pro-experimental">learnlm-1.5-pro-experimental</option> |
| 124 | <option data-type="vertexai" value="gemini-2.5-pro">gemini-2.5-pro</option> | ||
| 125 | <option data-type="vertexai" value="gemini-2.5-pro-preview-06-05">gemini-2.5-pro-preview-06-05</option> | ||
| 119 | <option data-type="vertexai" value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> | 126 | <option data-type="vertexai" value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> |
| 120 | <option data-type="vertexai" value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> | 127 | <option data-type="vertexai" value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> |
| 128 | <option data-type="vertexai" value="gemini-2.5-flash">gemini-2.5-flash</option> | ||
| 121 | <option data-type="vertexai" value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> | 129 | <option data-type="vertexai" value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> |
| 122 | <option data-type="vertexai" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | 130 | <option data-type="vertexai" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> |
| 131 | <option data-type="vertexai" value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> | ||
| 123 | <option data-type="vertexai" value="gemini-2.0-flash-001">gemini-2.0-flash-001</option> | 132 | <option data-type="vertexai" value="gemini-2.0-flash-001">gemini-2.0-flash-001</option> |
| 124 | <option data-type="vertexai" value="gemini-2.0-flash-lite-001">gemini-2.0-flash-lite-001</option> | 133 | <option data-type="vertexai" value="gemini-2.0-flash-lite-001">gemini-2.0-flash-lite-001</option> |
| 125 | <option data-type="groq" value="llama-3.2-11b-vision-preview">llama-3.2-11b-vision-preview</option> | 134 | <option data-type="groq" value="llama-3.2-11b-vision-preview">llama-3.2-11b-vision-preview</option> |
| 126 | <option data-type="groq" value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview</option> | 135 | <option data-type="groq" value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview</option> |
| 127 | <option data-type="groq" value="llava-v1.5-7b-4096-preview">llava-v1.5-7b-4096-preview</option> | 136 | <option data-type="groq" value="llava-v1.5-7b-4096-preview">llava-v1.5-7b-4096-preview</option> |
| 137 | <option data-type="aimlapi" value="gpt-4o-2024-05-13">gpt-4o-2024-05-13</option> | ||
| 138 | <option data-type="aimlapi" value="gpt-4o-2024-08-06">gpt-4o-2024-08-06</option> | ||
| 139 | <option data-type="aimlapi" value="gpt-4o">gpt-4o</option> | ||
| 140 | <option data-type="aimlapi" value="gpt-4o-mini">gpt-4o-mini</option> | ||
| 141 | <option data-type="aimlapi" value="gpt-4o-mini-2024-07-18">gpt-4o-mini-2024-07-18</option> | ||
| 142 | <option data-type="aimlapi" value="chatgpt-4o-latest">chatgpt-4o-latest</option> | ||
| 143 | <option data-type="aimlapi" value="gpt-4-turbo">gpt-4-turbo</option> | ||
| 144 | <option data-type="aimlapi" value="claude-3-opus-20240229">claude-3-opus-20240229</option> | ||
| 145 | <option data-type="aimlapi" value="claude-3-sonnet-20240229">claude-3-sonnet-20240229</option> | ||
| 146 | <option data-type="aimlapi" value="claude-3-haiku-20240307">claude-3-haiku-20240307</option> | ||
| 147 | <option data-type="aimlapi" value="claude-3-5-sonnet-20240620">claude-3-5-sonnet-20240620</option> | ||
| 148 | <option data-type="aimlapi" value="google/gemini-1.5-flash">google/gemini-1.5-flash</option> | ||
| 149 | <option data-type="aimlapi" value="google/gemini-1.5-pro">google/gemini-1.5-pro</option> | ||
| 150 | <option data-type="aimlapi" value="google/gemini-2.0-flash">google/gemini-2.0-flash</option> | ||
| 151 | <option data-type="aimlapi" value="google/gemini-2.0-flash-exp">google/gemini-2.0-flash-exp</option> | ||
| 152 | <option data-type="aimlapi" value="google/gemini-2.5-flash-preview">google/gemini-2.5-flash-preview</option> | ||
| 153 | <option data-type="aimlapi" value="meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo">meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo</option> | ||
| 154 | <option data-type="aimlapi" value="meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo">meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo</option> | ||
| 128 | <option data-type="openrouter" value="openai/gpt-4-vision-preview">openai/gpt-4-vision-preview</option> | 155 | <option data-type="openrouter" value="openai/gpt-4-vision-preview">openai/gpt-4-vision-preview</option> |
| 129 | <option data-type="openrouter" value="openai/gpt-4o">openai/gpt-4o</option> | 156 | <option data-type="openrouter" value="openai/gpt-4o">openai/gpt-4o</option> |
| 130 | <option data-type="openrouter" value="openai/gpt-4o-2024-05-13">openai/gpt-4o-2024-05-13</option> | 157 | <option data-type="openrouter" value="openai/gpt-4o-2024-05-13">openai/gpt-4o-2024-05-13</option> |
| @@ -13,6 +13,7 @@ import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js'; | |||
| 13 | import { SlashCommandScope } from '../../slash-commands/SlashCommandScope.js'; | 13 | import { SlashCommandScope } from '../../slash-commands/SlashCommandScope.js'; |
| 14 | import { collapseSpaces, getUniqueName, isFalseBoolean, uuidv4 } from '../../utils.js'; | 14 | import { collapseSpaces, getUniqueName, isFalseBoolean, uuidv4 } from '../../utils.js'; |
| 15 | import { t } from '../../i18n.js'; | 15 | import { t } from '../../i18n.js'; |
| 16 | import { getSecretLabelById } from '../../secrets.js'; | ||
| 16 | 17 | ||
| 17 | const MODULE_NAME = 'connection-manager'; | 18 | const MODULE_NAME = 'connection-manager'; |
| 18 | const NONE = '<None>'; | 19 | const NONE = '<None>'; |
| @@ -40,6 +41,8 @@ const CC_COMMANDS = [ | |||
| 40 | 'stop-strings', | 41 | 'stop-strings', |
| 41 | 'start-reply-with', | 42 | 'start-reply-with', |
| 42 | 'reasoning-template', | 43 | 'reasoning-template', |
| 44 | 'prompt-post-processing', | ||
| 45 | 'secret-id', | ||
| 43 | ]; | 46 | ]; |
| 44 | 47 | ||
| 45 | const TC_COMMANDS = [ | 48 | const TC_COMMANDS = [ |
| @@ -56,6 +59,7 @@ const TC_COMMANDS = [ | |||
| 56 | 'stop-strings', | 59 | 'stop-strings', |
| 57 | 'start-reply-with', | 60 | 'start-reply-with', |
| 58 | 'reasoning-template', | 61 | 'reasoning-template', |
| 62 | 'secret-id', | ||
| 59 | ]; | 63 | ]; |
| 60 | 64 | ||
| 61 | const FANCY_NAMES = { | 65 | const FANCY_NAMES = { |
| @@ -73,6 +77,8 @@ const FANCY_NAMES = { | |||
| 73 | 'stop-strings': 'Custom Stopping Strings', | 77 | 'stop-strings': 'Custom Stopping Strings', |
| 74 | 'start-reply-with': 'Start Reply With', | 78 | 'start-reply-with': 'Start Reply With', |
| 75 | 'reasoning-template': 'Reasoning Template', | 79 | 'reasoning-template': 'Reasoning Template', |
| 80 | 'prompt-post-processing': 'Prompt Post-Processing', | ||
| 81 | 'secret-id': 'Secret', | ||
| 76 | }; | 82 | }; |
| 77 | 83 | ||
| 78 | /** | 84 | /** |
| @@ -342,6 +348,15 @@ function makeFancyProfile(profile) { | |||
| 342 | return acc; | 348 | return acc; |
| 343 | } | 349 | } |
| 344 | 350 | ||
| 351 | // UUID is not very useful in the UI, so we replace it with a label (if available) | ||
| 352 | if (key === 'secret-id') { | ||
| 353 | const label = getSecretLabelById(profile[key]); | ||
| 354 | if (label) { | ||
| 355 | acc[value] = label; | ||
| 356 | return acc; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 345 | acc[value] = profile[key]; | 360 | acc[value] = profile[key]; |
| 346 | return acc; | 361 | return acc; |
| 347 | }, {}); | 362 | }, {}); |
| @@ -1,6 +1,6 @@ | |||
| 1 | import { Fuse } from '../../../lib.js'; | 1 | import { Fuse } from '../../../lib.js'; |
| 2 | 2 | ||
| 3 | import { characters, eventSource, event_types, generateRaw, getRequestHeaders, main_api, online_status, saveSettingsDebounced, substituteParams, substituteParamsExtended, system_message_types, this_chid } from '../../../script.js'; | 3 | import { characters, eventSource, event_types, generateQuietPrompt, generateRaw, getRequestHeaders, main_api, online_status, saveSettingsDebounced, substituteParams, substituteParamsExtended, system_message_types, this_chid } from '../../../script.js'; |
| 4 | import { dragElement, isMobile } from '../../RossAscends-mods.js'; | 4 | import { dragElement, isMobile } from '../../RossAscends-mods.js'; |
| 5 | import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js'; | 5 | import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js'; |
| 6 | import { loadMovingUIState, performFuzzySearch, power_user } from '../../power-user.js'; | 6 | import { loadMovingUIState, performFuzzySearch, power_user } from '../../power-user.js'; |
| @@ -86,6 +86,12 @@ const EXPRESSION_API = { | |||
| 86 | none: 99, | 86 | none: 99, |
| 87 | }; | 87 | }; |
| 88 | 88 | ||
| 89 | /** @enum {string} */ | ||
| 90 | const PROMPT_TYPE = { | ||
| 91 | raw: 'raw', | ||
| 92 | full: 'full', | ||
| 93 | }; | ||
| 94 | |||
| 89 | let expressionsList = null; | 95 | let expressionsList = null; |
| 90 | let lastCharacter = undefined; | 96 | let lastCharacter = undefined; |
| 91 | let lastMessage = null; | 97 | let lastMessage = null; |
| @@ -909,10 +915,6 @@ function sampleClassifyText(text) { | |||
| 909 | * @returns {Promise<string>} Prompt for the LLM API. | 915 | * @returns {Promise<string>} Prompt for the LLM API. |
| 910 | */ | 916 | */ |
| 911 | async function getLlmPrompt(labels) { | 917 | async function getLlmPrompt(labels) { |
| 912 | if (isJsonSchemaSupported()) { | ||
| 913 | return ''; | ||
| 914 | } | ||
| 915 | |||
| 916 | const labelsString = labels.map(x => `"${x}"`).join(', '); | 918 | const labelsString = labels.map(x => `"${x}"`).join(', '); |
| 917 | const prompt = substituteParamsExtended(String(extension_settings.expressions.llmPrompt), { labels: labelsString }); | 919 | const prompt = substituteParamsExtended(String(extension_settings.expressions.llmPrompt), { labels: labelsString }); |
| 918 | return prompt; | 920 | return prompt; |
| @@ -976,6 +978,7 @@ function getJsonSchema(emotions) { | |||
| 976 | required: [ | 978 | required: [ |
| 977 | 'emotion', | 979 | 'emotion', |
| 978 | ], | 980 | ], |
| 981 | additionalProperties: false, | ||
| 979 | }; | 982 | }; |
| 980 | } | 983 | } |
| 981 | 984 | ||
| @@ -1047,7 +1050,21 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin | |||
| 1047 | const expressionsList = await getExpressionsList({ filterAvailable: filterAvailable }); | 1050 | const expressionsList = await getExpressionsList({ filterAvailable: filterAvailable }); |
| 1048 | const prompt = substituteParamsExtended(customPrompt, { labels: expressionsList }) || await getLlmPrompt(expressionsList); | 1051 | const prompt = substituteParamsExtended(customPrompt, { labels: expressionsList }) || await getLlmPrompt(expressionsList); |
| 1049 | eventSource.once(event_types.TEXT_COMPLETION_SETTINGS_READY, onTextGenSettingsReady); | 1052 | eventSource.once(event_types.TEXT_COMPLETION_SETTINGS_READY, onTextGenSettingsReady); |
| 1050 | const emotionResponse = await generateRaw(text, main_api, false, false, prompt); | 1053 | |
| 1054 | let emotionResponse; | ||
| 1055 | try { | ||
| 1056 | inApiCall = true; | ||
| 1057 | switch (extension_settings.expressions.promptType) { | ||
| 1058 | case PROMPT_TYPE.raw: | ||
| 1059 | emotionResponse = await generateRaw(text, main_api, false, false, prompt); | ||
| 1060 | break; | ||
| 1061 | case PROMPT_TYPE.full: | ||
| 1062 | emotionResponse = await generateQuietPrompt(prompt, false, false); | ||
| 1063 | break; | ||
| 1064 | } | ||
| 1065 | } finally { | ||
| 1066 | inApiCall = false; | ||
| 1067 | } | ||
| 1051 | return parseLlmResponse(emotionResponse, expressionsList); | 1068 | return parseLlmResponse(emotionResponse, expressionsList); |
| 1052 | } | 1069 | } |
| 1053 | // Using WebLLM | 1070 | // Using WebLLM |
| @@ -1702,6 +1719,7 @@ function onExpressionApiChanged() { | |||
| 1702 | if (tempApi) { | 1719 | if (tempApi) { |
| 1703 | extension_settings.expressions.api = Number(tempApi); | 1720 | extension_settings.expressions.api = Number(tempApi); |
| 1704 | $('.expression_llm_prompt_block').toggle([EXPRESSION_API.llm, EXPRESSION_API.webllm].includes(extension_settings.expressions.api)); | 1721 | $('.expression_llm_prompt_block').toggle([EXPRESSION_API.llm, EXPRESSION_API.webllm].includes(extension_settings.expressions.api)); |
| 1722 | $('.expression_prompt_type_block').toggle(extension_settings.expressions.api === EXPRESSION_API.llm); | ||
| 1705 | expressionsList = null; | 1723 | expressionsList = null; |
| 1706 | spriteCache = {}; | 1724 | spriteCache = {}; |
| 1707 | moduleWorker(); | 1725 | moduleWorker(); |
| @@ -2102,6 +2120,11 @@ function migrateSettings() { | |||
| 2102 | extension_settings.expressions.showDefault = false; | 2120 | extension_settings.expressions.showDefault = false; |
| 2103 | saveSettingsDebounced(); | 2121 | saveSettingsDebounced(); |
| 2104 | } | 2122 | } |
| 2123 | |||
| 2124 | if (extension_settings.expressions.promptType === undefined) { | ||
| 2125 | extension_settings.expressions.promptType = PROMPT_TYPE.raw; | ||
| 2126 | saveSettingsDebounced(); | ||
| 2127 | } | ||
| 2105 | } | 2128 | } |
| 2106 | 2129 | ||
| 2107 | (async function () { | 2130 | (async function () { |
| @@ -2169,6 +2192,16 @@ function migrateSettings() { | |||
| 2169 | extension_settings.expressions.llmPrompt = DEFAULT_LLM_PROMPT; | 2192 | extension_settings.expressions.llmPrompt = DEFAULT_LLM_PROMPT; |
| 2170 | saveSettingsDebounced(); | 2193 | saveSettingsDebounced(); |
| 2171 | }); | 2194 | }); |
| 2195 | $('#expression_prompt_raw').on('input', function () { | ||
| 2196 | extension_settings.expressions.promptType = PROMPT_TYPE.raw; | ||
| 2197 | saveSettingsDebounced(); | ||
| 2198 | }); | ||
| 2199 | $('#expression_prompt_full').on('input', function () { | ||
| 2200 | extension_settings.expressions.promptType = PROMPT_TYPE.full; | ||
| 2201 | saveSettingsDebounced(); | ||
| 2202 | }); | ||
| 2203 | $(`input[name="expression_prompt_type"][value="${extension_settings.expressions.promptType}"]`).prop('checked', true); | ||
| 2204 | $('.expression_prompt_type_block').toggle(extension_settings.expressions.api === EXPRESSION_API.llm); | ||
| 2172 | 2205 | ||
| 2173 | $('#expression_custom_add').on('click', onClickExpressionAddCustom); | 2206 | $('#expression_custom_add').on('click', onClickExpressionAddCustom); |
| 2174 | $('#expression_custom_remove').on('click', onClickExpressionRemoveCustom); | 2207 | $('#expression_custom_remove').on('click', onClickExpressionRemoveCustom); |
| @@ -40,8 +40,21 @@ | |||
| 40 | <i class="fa-solid fa-clock-rotate-left fa-sm"></i> | 40 | <i class="fa-solid fa-clock-rotate-left fa-sm"></i> |
| 41 | </div> | 41 | </div> |
| 42 | </label> | 42 | </label> |
| 43 | <small data-i18n="Will be used if the API doesn't support JSON schemas or function calling.">Will be used if the API doesn't support JSON schemas or function calling.</small> | 43 | <small data-i18n="Used in addition to JSON schemas and function calling.">Used in addition to JSON schemas and function calling.</small> |
| 44 | <textarea id="expression_llm_prompt" type="text" class="text_pole textarea_compact" rows="2" placeholder="Use {{labels}} special macro."></textarea> | 44 | <textarea id="expression_llm_prompt" type="text" class="text_pole textarea_compact autoSetHeight" rows="2" placeholder="Use {{labels}} special macro."></textarea> |
| 45 | </div> | ||
| 46 | <div class="expression_prompt_type_block flex-container flexFlowColumn"> | ||
| 47 | <div data-i18n="LLM Prompt Strategy" class="title_restorable"> | ||
| 48 | LLM Prompt Strategy | ||
| 49 | </div> | ||
| 50 | <label for="expression_prompt_raw" class="checkbox_label"> | ||
| 51 | <input id="expression_prompt_raw" type="radio" name="expression_prompt_type" value="raw"> | ||
| 52 | <span data-i18n="Limited Context">Limited Context</span> | ||
| 53 | </label> | ||
| 54 | <label for="expression_prompt_full" class="checkbox_label"> | ||
| 55 | <input id="expression_prompt_full" type="radio" name="expression_prompt_type" value="full"> | ||
| 56 | <span data-i18n="Full Context">Full Context</span> | ||
| 57 | </label> | ||
| 45 | </div> | 58 | </div> |
| 46 | <div class="expression_fallback_block m-b-1 m-t-1"> | 59 | <div class="expression_fallback_block m-b-1 m-t-1"> |
| 47 | <label for="expression_fallback" data-i18n="Default / Fallback Expression">Default / Fallback Expression</label> | 60 | <label for="expression_fallback" data-i18n="Default / Fallback Expression">Default / Fallback Expression</label> |
| @@ -52,7 +65,7 @@ | |||
| 52 | <label for="expression_custom" data-i18n="Custom Expressions">Custom Expressions</label> | 65 | <label for="expression_custom" data-i18n="Custom Expressions">Custom Expressions</label> |
| 53 | <small><span data-i18n="Can be set manually or with an _space">Can be set manually or with an </span><tt>/emote</tt><span data-i18n="space_ slash command."> slash command.</span></small> | 66 | <small><span data-i18n="Can be set manually or with an _space">Can be set manually or with an </span><tt>/emote</tt><span data-i18n="space_ slash command."> slash command.</span></small> |
| 54 | <div class="flex-container"> | 67 | <div class="flex-container"> |
| 55 | <select id="expression_custom" class="flex1 margin0"><select> | 68 | <select id="expression_custom" class="flex1 margin0"></select> |
| 56 | <i id="expression_custom_add" class="menu_button fa-solid fa-plus margin0" title="Add"></i> | 69 | <i id="expression_custom_add" class="menu_button fa-solid fa-plus margin0" title="Add"></i> |
| 57 | <i id="expression_custom_remove" class="menu_button fa-solid fa-xmark margin0" title="Remove"></i> | 70 | <i id="expression_custom_remove" class="menu_button fa-solid fa-xmark margin0" title="Remove"></i> |
| 58 | </div> | 71 | </div> |
| @@ -4,6 +4,8 @@ import { | |||
| 4 | characters, | 4 | characters, |
| 5 | getRequestHeaders, | 5 | getRequestHeaders, |
| 6 | event_types, | 6 | event_types, |
| 7 | animation_duration, | ||
| 8 | animation_easing, | ||
| 7 | } from '../../../script.js'; | 9 | } from '../../../script.js'; |
| 8 | import { groups, selected_group } from '../../group-chats.js'; | 10 | import { groups, selected_group } from '../../group-chats.js'; |
| 9 | import { loadFileToDocument, delay, getBase64Async, getSanitizedFilename } from '../../utils.js'; | 11 | import { loadFileToDocument, delay, getBase64Async, getSanitizedFilename } from '../../utils.js'; |
| @@ -15,10 +17,12 @@ import { ARGUMENT_TYPE, SlashCommandNamedArgument } from '../../slash-commands/S | |||
| 15 | import { DragAndDropHandler } from '../../dragdrop.js'; | 17 | import { DragAndDropHandler } from '../../dragdrop.js'; |
| 16 | import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; | 18 | import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 17 | import { t, translate } from '../../i18n.js'; | 19 | import { t, translate } from '../../i18n.js'; |
| 20 | import { Popup } from '../../popup.js'; | ||
| 18 | 21 | ||
| 19 | const extensionName = 'gallery'; | 22 | const extensionName = 'gallery'; |
| 20 | const extensionFolderPath = `scripts/extensions/${extensionName}/`; | 23 | const extensionFolderPath = `scripts/extensions/${extensionName}/`; |
| 21 | let firstTime = true; | 24 | let firstTime = true; |
| 25 | let deleteModeActive = false; | ||
| 22 | 26 | ||
| 23 | // Exposed defaults for future tweaking | 27 | // Exposed defaults for future tweaking |
| 24 | let thumbnailHeight = 150; | 28 | let thumbnailHeight = 150; |
| @@ -30,7 +34,15 @@ let galleryMaxRows = 3; | |||
| 30 | $('#movingDivs').on('click', '.dragClose', function () { | 34 | $('#movingDivs').on('click', '.dragClose', function () { |
| 31 | const relatedId = $(this).data('related-id'); | 35 | const relatedId = $(this).data('related-id'); |
| 32 | if (!relatedId) return; | 36 | if (!relatedId) return; |
| 33 | $(`#movingDivs > .draggable[id="${relatedId}"]`).remove(); | 37 | const relatedElement = $(`#movingDivs > .draggable[id="${relatedId}"]`); |
| 38 | relatedElement.transition({ | ||
| 39 | opacity: 0, | ||
| 40 | duration: animation_duration, | ||
| 41 | easing: animation_easing, | ||
| 42 | complete: () => { | ||
| 43 | relatedElement.remove(); | ||
| 44 | }, | ||
| 45 | }); | ||
| 34 | }); | 46 | }); |
| 35 | 47 | ||
| 36 | const CUSTOM_GALLERY_REMOVED_EVENT = 'galleryRemoved'; | 48 | const CUSTOM_GALLERY_REMOVED_EVENT = 'galleryRemoved'; |
| @@ -147,6 +159,29 @@ async function getGalleryFolders() { | |||
| 147 | } | 159 | } |
| 148 | 160 | ||
| 149 | /** | 161 | /** |
| 162 | * Deletes a gallery item based on the provided URL. | ||
| 163 | * @param {string} url - The URL of the image to be deleted. | ||
| 164 | */ | ||
| 165 | async function deleteGalleryItem(url) { | ||
| 166 | try { | ||
| 167 | const response = await fetch('/api/images/delete', { | ||
| 168 | method: 'POST', | ||
| 169 | headers: getRequestHeaders(), | ||
| 170 | body: JSON.stringify({ path: url }), | ||
| 171 | }); | ||
| 172 | |||
| 173 | if (!response.ok) { | ||
| 174 | throw new Error(`HTTP error. Status: ${response.status}`); | ||
| 175 | } | ||
| 176 | |||
| 177 | toastr.success(t`Image deleted successfully.`); | ||
| 178 | } catch (error) { | ||
| 179 | console.error('Failed to delete the image:', error); | ||
| 180 | toastr.error(t`Failed to delete the image. Check the console for details.`); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 150 | * Sets the sort order for the gallery. | 185 | * Sets the sort order for the gallery. |
| 151 | * @param {string} order Sort order | 186 | * @param {string} order Sort order |
| 152 | */ | 187 | */ |
| @@ -260,7 +295,7 @@ async function initGallery(items, url) { | |||
| 260 | * | 295 | * |
| 261 | * @returns {Promise<void>} - Promise representing the completion of the gallery display process. | 296 | * @returns {Promise<void>} - Promise representing the completion of the gallery display process. |
| 262 | */ | 297 | */ |
| 263 | async function showCharGallery() { | 298 | async function showCharGallery(deleteModeState = false) { |
| 264 | // Load necessary files if it's the first time calling the function | 299 | // Load necessary files if it's the first time calling the function |
| 265 | if (firstTime) { | 300 | if (firstTime) { |
| 266 | await loadFileToDocument( | 301 | await loadFileToDocument( |
| @@ -276,6 +311,7 @@ async function showCharGallery() { | |||
| 276 | } | 311 | } |
| 277 | 312 | ||
| 278 | try { | 313 | try { |
| 314 | deleteModeActive = deleteModeState; | ||
| 279 | let url = selected_group || this_chid; | 315 | let url = selected_group || this_chid; |
| 280 | if (!selected_group && this_chid !== undefined) { | 316 | if (!selected_group && this_chid !== undefined) { |
| 281 | url = getGalleryFolder(characters[this_chid]); | 317 | url = getGalleryFolder(characters[this_chid]); |
| @@ -347,7 +383,7 @@ async function makeMovable(url) { | |||
| 347 | const id = 'gallery'; | 383 | const id = 'gallery'; |
| 348 | const template = $('#generic_draggable_template').html(); | 384 | const template = $('#generic_draggable_template').html(); |
| 349 | const newElement = $(template); | 385 | const newElement = $(template); |
| 350 | newElement.css('background-color', 'var(--SmartThemeBlurTintColor)'); | 386 | newElement.css({ 'background-color': 'var(--SmartThemeBlurTintColor)', 'opacity': 0 }); |
| 351 | newElement.attr('forChar', id); | 387 | newElement.attr('forChar', id); |
| 352 | newElement.attr('id', id); | 388 | newElement.attr('id', id); |
| 353 | newElement.find('.drag-grabber').attr('id', `${id}header`); | 389 | newElement.find('.drag-grabber').attr('id', `${id}header`); |
| @@ -429,6 +465,18 @@ async function makeMovable(url) { | |||
| 429 | galleryFolderAccept.title = t`Change gallery folder`; | 465 | galleryFolderAccept.title = t`Change gallery folder`; |
| 430 | galleryFolderAccept.addEventListener('click', onChangeFolder); | 466 | galleryFolderAccept.addEventListener('click', onChangeFolder); |
| 431 | 467 | ||
| 468 | const galleryDeleteMode = document.createElement('div'); | ||
| 469 | galleryDeleteMode.classList.add('right_menu_button', 'fa-solid', 'fa-trash', 'fa-fw'); | ||
| 470 | galleryDeleteMode.classList.toggle('warning', deleteModeActive); | ||
| 471 | galleryDeleteMode.title = t`Delete mode`; | ||
| 472 | galleryDeleteMode.addEventListener('click', () => { | ||
| 473 | deleteModeActive = !deleteModeActive; | ||
| 474 | galleryDeleteMode.classList.toggle('warning', deleteModeActive); | ||
| 475 | if (deleteModeActive) { | ||
| 476 | toastr.info(t`Delete mode is ON. Click on images you want to delete.`); | ||
| 477 | } | ||
| 478 | }); | ||
| 479 | |||
| 432 | const galleryFolderRestore = document.createElement('div'); | 480 | const galleryFolderRestore = document.createElement('div'); |
| 433 | galleryFolderRestore.classList.add('right_menu_button', 'fa-solid', 'fa-recycle', 'fa-fw'); | 481 | galleryFolderRestore.classList.add('right_menu_button', 'fa-solid', 'fa-recycle', 'fa-fw'); |
| 434 | galleryFolderRestore.title = t`Restore gallery folder`; | 482 | galleryFolderRestore.title = t`Restore gallery folder`; |
| @@ -436,6 +484,7 @@ async function makeMovable(url) { | |||
| 436 | 484 | ||
| 437 | topBarElement.appendChild(galleryFolderInput); | 485 | topBarElement.appendChild(galleryFolderInput); |
| 438 | topBarElement.appendChild(galleryFolderAccept); | 486 | topBarElement.appendChild(galleryFolderAccept); |
| 487 | topBarElement.appendChild(galleryDeleteMode); | ||
| 439 | topBarElement.appendChild(galleryFolderRestore); | 488 | topBarElement.appendChild(galleryFolderRestore); |
| 440 | newElement.append(topBarElement); | 489 | newElement.append(topBarElement); |
| 441 | 490 | ||
| @@ -466,6 +515,11 @@ async function makeMovable(url) { | |||
| 466 | loadMovingUIState(); | 515 | loadMovingUIState(); |
| 467 | $(`.draggable[forChar="${id}"]`).css('display', 'block'); | 516 | $(`.draggable[forChar="${id}"]`).css('display', 'block'); |
| 468 | dragElement(newElement); | 517 | dragElement(newElement); |
| 518 | newElement.transition({ | ||
| 519 | opacity: 1, | ||
| 520 | duration: animation_duration, | ||
| 521 | easing: animation_easing, | ||
| 522 | }); | ||
| 469 | 523 | ||
| 470 | $(`.draggable[forChar="${id}"] img`).on('dragstart', (e) => { | 524 | $(`.draggable[forChar="${id}"] img`).on('dragstart', (e) => { |
| 471 | console.log('saw drag on avatar!'); | 525 | console.log('saw drag on avatar!'); |
| @@ -635,9 +689,19 @@ function sanitizeHTMLId(id) { | |||
| 635 | function viewWithDragbox(items) { | 689 | function viewWithDragbox(items) { |
| 636 | if (items && items.length > 0) { | 690 | if (items && items.length > 0) { |
| 637 | const url = items[0].responsiveURL(); // Get the URL of the clicked image/video | 691 | const url = items[0].responsiveURL(); // Get the URL of the clicked image/video |
| 638 | // ID should just be the last part of the URL, removing the extension | 692 | if (deleteModeActive) { |
| 639 | const id = sanitizeHTMLId(url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.'))); | 693 | Popup.show.confirm(t`Are you sure you want to delete this image?`, url) |
| 640 | makeDragImg(id, url); | 694 | .then(async (confirmed) => { |
| 695 | if (!confirmed) { | ||
| 696 | return; | ||
| 697 | } | ||
| 698 | deleteGalleryItem(url).then(() => showCharGallery(deleteModeActive)); | ||
| 699 | }); | ||
| 700 | } else { | ||
| 701 | // ID should just be the last part of the URL, removing the extension | ||
| 702 | const id = sanitizeHTMLId(url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.'))); | ||
| 703 | makeDragImg(id, url); | ||
| 704 | } | ||
| 641 | } | 705 | } |
| 642 | } | 706 | } |
| 643 | 707 | ||
| @@ -43,3 +43,8 @@ | |||
| 43 | #dragGallery { | 43 | #dragGallery { |
| 44 | min-height: 25dvh; | 44 | min-height: 25dvh; |
| 45 | } | 45 | } |
| 46 | |||
| 47 | #gallery .right_menu_button.warning { | ||
| 48 | opacity: 1; | ||
| 49 | filter: unset; | ||
| 50 | } | ||
| @@ -16,6 +16,7 @@ import { | |||
| 16 | getMaxContextSize, | 16 | getMaxContextSize, |
| 17 | setExtensionPrompt, | 17 | setExtensionPrompt, |
| 18 | streamingProcessor, | 18 | streamingProcessor, |
| 19 | animation_easing, | ||
| 19 | } from '../../../script.js'; | 20 | } from '../../../script.js'; |
| 20 | import { is_group_generating, selected_group } from '../../group-chats.js'; | 21 | import { is_group_generating, selected_group } from '../../group-chats.js'; |
| 21 | import { loadMovingUIState } from '../../power-user.js'; | 22 | import { loadMovingUIState } from '../../power-user.js'; |
| @@ -972,6 +973,7 @@ function doPopout(e) { | |||
| 972 | </div>`; | 973 | </div>`; |
| 973 | const newElement = $(template); | 974 | const newElement = $(template); |
| 974 | newElement.attr('id', 'summaryExtensionPopout') | 975 | newElement.attr('id', 'summaryExtensionPopout') |
| 976 | .css('opacity', 0) | ||
| 975 | .removeClass('zoomed_avatar') | 977 | .removeClass('zoomed_avatar') |
| 976 | .addClass('draggable') | 978 | .addClass('draggable') |
| 977 | .empty(); | 979 | .empty(); |
| @@ -980,13 +982,13 @@ function doPopout(e) { | |||
| 980 | originalElement.html('<div class="flex-container alignitemscenter justifyCenter wide100p"><small>Currently popped out</small></div>'); | 982 | originalElement.html('<div class="flex-container alignitemscenter justifyCenter wide100p"><small>Currently popped out</small></div>'); |
| 981 | newElement.append(controlBarHtml).append(originalHTMLClone); | 983 | newElement.append(controlBarHtml).append(originalHTMLClone); |
| 982 | $('body').append(newElement); | 984 | $('body').append(newElement); |
| 985 | newElement.transition({ opacity: 1, duration: animation_duration, easing: animation_easing }); | ||
| 983 | $('#summaryExtensionDrawerContents').addClass('scrollableInnerFull'); | 986 | $('#summaryExtensionDrawerContents').addClass('scrollableInnerFull'); |
| 984 | setMemoryContext(prevSummaryBoxContents, false); //paste prev summary box contents into popout box | 987 | setMemoryContext(prevSummaryBoxContents, false); //paste prev summary box contents into popout box |
| 985 | setupListeners(); | 988 | setupListeners(); |
| 986 | loadSettings(); | 989 | loadSettings(); |
| 987 | loadMovingUIState(); | 990 | loadMovingUIState(); |
| 988 | 991 | ||
| 989 | $('#summaryExtensionPopout').fadeIn(animation_duration); | ||
| 990 | dragElement(newElement); | 992 | dragElement(newElement); |
| 991 | 993 | ||
| 992 | //setup listener for close button to restore extensions menu | 994 | //setup listener for close button to restore extensions menu |
| @@ -181,7 +181,7 @@ const init = async () => { | |||
| 181 | 181 | ||
| 182 | eventSource.on(event_types.APP_READY, async()=>await finalizeInit()); | 182 | eventSource.on(event_types.APP_READY, async()=>await finalizeInit()); |
| 183 | 183 | ||
| 184 | window['quickReplyApi'] = quickReplyApi; | 184 | globalThis.quickReplyApi = quickReplyApi; |
| 185 | }; | 185 | }; |
| 186 | const finalizeInit = async () => { | 186 | const finalizeInit = async () => { |
| 187 | debug('executing startup'); | 187 | debug('executing startup'); |
| @@ -18,7 +18,7 @@ | |||
| 18 | #qr--bar { | 18 | #qr--bar { |
| 19 | outline: none; | 19 | outline: none; |
| 20 | margin: 0; | 20 | margin: 0; |
| 21 | transition: 0.3s; | 21 | transition: var(--animation-duration-2x); |
| 22 | opacity: 0.7; | 22 | opacity: 0.7; |
| 23 | display: flex; | 23 | display: flex; |
| 24 | align-items: center; | 24 | align-items: center; |
| @@ -34,14 +34,12 @@ | |||
| 34 | right: 0.25em; | 34 | right: 0.25em; |
| 35 | top: 0; | 35 | top: 0; |
| 36 | } | 36 | } |
| 37 | |||
| 38 | /*hide QR popout for mobile*/ | 37 | /*hide QR popout for mobile*/ |
| 39 | @media screen and (max-width: 1000px) { | 38 | @media screen and (max-width: 1000px) { |
| 40 | #qr--bar > #qr--popoutTrigger { | 39 | #qr--bar > #qr--popoutTrigger { |
| 41 | display:none; | 40 | display: none; |
| 42 | } | 41 | } |
| 43 | } | 42 | } |
| 44 | |||
| 45 | #qr--bar.popoutVisible { | 43 | #qr--bar.popoutVisible { |
| 46 | padding-right: 2.5em; | 44 | padding-right: 2.5em; |
| 47 | } | 45 | } |
| @@ -61,9 +59,8 @@ | |||
| 61 | aspect-ratio: 1 / 1; | 59 | aspect-ratio: 1 / 1; |
| 62 | font-size: 20px; | 60 | font-size: 20px; |
| 63 | opacity: 0.5; | 61 | opacity: 0.5; |
| 64 | transition: all 250ms; | 62 | transition: all var(--animation-duration-2x); |
| 65 | } | 63 | } |
| 66 | |||
| 67 | #qr--popout > .qr--body { | 64 | #qr--popout > .qr--body { |
| 68 | overflow-y: auto; | 65 | overflow-y: auto; |
| 69 | } | 66 | } |
| @@ -124,7 +121,7 @@ | |||
| 124 | padding: 3px 5px; | 121 | padding: 3px 5px; |
| 125 | margin: 3px 0; | 122 | margin: 3px 0; |
| 126 | cursor: pointer; | 123 | cursor: pointer; |
| 127 | transition: 0.3s; | 124 | transition: var(--animation-duration-2x); |
| 128 | display: flex; | 125 | display: flex; |
| 129 | align-items: center; | 126 | align-items: center; |
| 130 | justify-content: center; | 127 | justify-content: center; |
| @@ -175,7 +172,7 @@ | |||
| 175 | overflow: visible; | 172 | overflow: visible; |
| 176 | } | 173 | } |
| 177 | .ctx-menu .ctx-item .qr--hidden { | 174 | .ctx-menu .ctx-item .qr--hidden { |
| 178 | display: none; | 175 | display: none; |
| 179 | } | 176 | } |
| 180 | .list-group .list-group-item.ctx-header { | 177 | .list-group .list-group-item.ctx-header { |
| 181 | font-weight: bold; | 178 | font-weight: bold; |
| @@ -248,7 +245,7 @@ | |||
| 248 | display: flex; | 245 | display: flex; |
| 249 | align-items: center; | 246 | align-items: center; |
| 250 | opacity: 0; | 247 | opacity: 0; |
| 251 | transition: 100ms; | 248 | transition: var(--animation-duration); |
| 252 | margin: -2px 0 -11px 0; | 249 | margin: -2px 0 -11px 0; |
| 253 | position: relative; | 250 | position: relative; |
| 254 | } | 251 | } |
| @@ -461,7 +458,7 @@ | |||
| 461 | cursor: not-allowed; | 458 | cursor: not-allowed; |
| 462 | opacity: 0.5; | 459 | opacity: 0.5; |
| 463 | pointer-events: none; | 460 | pointer-events: none; |
| 464 | transition: 200ms; | 461 | transition: var(--animation-duration-2x); |
| 465 | border-color: transparent; | 462 | border-color: transparent; |
| 466 | } | 463 | } |
| 467 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting.qr--isPaused #qr--modal-debugButtons .menu_button:not(#qr--modal-minimize, #qr--modal-maximize) { | 464 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting.qr--isPaused #qr--modal-debugButtons .menu_button:not(#qr--modal-minimize, #qr--modal-maximize) { |
| @@ -492,7 +489,7 @@ | |||
| 492 | width: 6px; | 489 | width: 6px; |
| 493 | background-color: var(--SmartThemeBorderColor); | 490 | background-color: var(--SmartThemeBorderColor); |
| 494 | border: 2px solid var(--SmartThemeBlurTintColor); | 491 | border: 2px solid var(--SmartThemeBlurTintColor); |
| 495 | transition: border-color 200ms, background-color 200ms; | 492 | transition: border-color var(--animation-duration-2x), background-color var(--animation-duration-2x); |
| 496 | cursor: w-resize; | 493 | cursor: w-resize; |
| 497 | } | 494 | } |
| 498 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--resizeHandle:hover { | 495 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--resizeHandle:hover { |
| @@ -574,7 +571,7 @@ | |||
| 574 | gap: 1em; | 571 | gap: 1em; |
| 575 | text-align: left; | 572 | text-align: left; |
| 576 | opacity: 0.75; | 573 | opacity: 0.75; |
| 577 | transition: 200ms; | 574 | transition: var(--animation-duration-2x); |
| 578 | cursor: pointer; | 575 | cursor: pointer; |
| 579 | } | 576 | } |
| 580 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--labels > label .qr--modal-switcherList .qr--modal-switcherItem:hover, | 577 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--labels > label .qr--modal-switcherList .qr--modal-switcherItem:hover, |
| @@ -736,7 +733,7 @@ | |||
| 736 | display: flex; | 733 | display: flex; |
| 737 | } | 734 | } |
| 738 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-executeButtons #qr--modal-execute { | 735 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-executeButtons #qr--modal-execute { |
| 739 | transition: 200ms; | 736 | transition: var(--animation-duration-2x); |
| 740 | filter: grayscale(0); | 737 | filter: grayscale(0); |
| 741 | } | 738 | } |
| 742 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-executeButtons #qr--modal-execute.qr--busy { | 739 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-executeButtons #qr--modal-execute.qr--busy { |
| @@ -825,7 +822,7 @@ | |||
| 825 | position: absolute; | 822 | position: absolute; |
| 826 | inset: 0; | 823 | inset: 0; |
| 827 | right: calc(100% - var(--prog) * 1%); | 824 | right: calc(100% - var(--prog) * 1%); |
| 828 | transition: 200ms; | 825 | transition: var(--animation-duration-2x); |
| 829 | } | 826 | } |
| 830 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-executeProgress.qr--paused:after { | 827 | .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-executeProgress.qr--paused:after { |
| 831 | animation-name: qr--progressPulse; | 828 | animation-name: qr--progressPulse; |
| @@ -1053,7 +1050,7 @@ | |||
| 1053 | white-space: pre; | 1050 | white-space: pre; |
| 1054 | font-weight: normal; | 1051 | font-weight: normal; |
| 1055 | box-shadow: 0 0 0; | 1052 | box-shadow: 0 0 0; |
| 1056 | transition: 200ms; | 1053 | transition: var(--animation-duration-2x); |
| 1057 | } | 1054 | } |
| 1058 | .popup:has(.qr--transferModal) .popup-button-ok:after { | 1055 | .popup:has(.qr--transferModal) .popup-button-ok:after { |
| 1059 | content: 'Transfer'; | 1056 | content: 'Transfer'; |
| @@ -1068,7 +1065,7 @@ | |||
| 1068 | white-space: pre; | 1065 | white-space: pre; |
| 1069 | font-weight: normal; | 1066 | font-weight: normal; |
| 1070 | box-shadow: 0 0 0; | 1067 | box-shadow: 0 0 0; |
| 1071 | transition: 200ms; | 1068 | transition: var(--animation-duration-2x); |
| 1072 | } | 1069 | } |
| 1073 | .popup:has(.qr--transferModal) .qr--copy:after { | 1070 | .popup:has(.qr--transferModal) .qr--copy:after { |
| 1074 | content: 'Copy'; | 1071 | content: 'Copy'; |
| @@ -1,11 +1,16 @@ | |||
| 1 | @keyframes qr--success { | 1 | @keyframes qr--success { |
| 2 | 0%, 100% { | 2 | |
| 3 | 0%, | ||
| 4 | 100% { | ||
| 3 | color: var(--SmartThemeBodyColor); | 5 | color: var(--SmartThemeBodyColor); |
| 4 | } | 6 | } |
| 5 | 25%, 75% { | 7 | |
| 8 | 25%, | ||
| 9 | 75% { | ||
| 6 | color: rgb(81, 163, 81); | 10 | color: rgb(81, 163, 81); |
| 7 | } | 11 | } |
| 8 | } | 12 | } |
| 13 | |||
| 9 | &.qr--success { | 14 | &.qr--success { |
| 10 | animation-name: qr--success; | 15 | animation-name: qr--success; |
| 11 | animation-duration: 3s; | 16 | animation-duration: 3s; |
| @@ -13,10 +18,11 @@ | |||
| 13 | animation-delay: 0s; | 18 | animation-delay: 0s; |
| 14 | animation-iteration-count: 1; | 19 | animation-iteration-count: 1; |
| 15 | } | 20 | } |
| 21 | |||
| 16 | #qr--bar { | 22 | #qr--bar { |
| 17 | outline: none; | 23 | outline: none; |
| 18 | margin: 0; | 24 | margin: 0; |
| 19 | transition: 0.3s; | 25 | transition: var(--animation-duration-2x); |
| 20 | opacity: 0.7; | 26 | opacity: 0.7; |
| 21 | display: flex; | 27 | display: flex; |
| 22 | align-items: center; | 28 | align-items: center; |
| @@ -33,6 +39,14 @@ | |||
| 33 | top: 0; | 39 | top: 0; |
| 34 | } | 40 | } |
| 35 | } | 41 | } |
| 42 | |||
| 43 | /*hide QR popout for mobile*/ | ||
| 44 | @media screen and (max-width: 1000px) { | ||
| 45 | #qr--bar>#qr--popoutTrigger { | ||
| 46 | display: none; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 36 | #qr--bar.popoutVisible { | 50 | #qr--bar.popoutVisible { |
| 37 | padding-right: 2.5em; | 51 | padding-right: 2.5em; |
| 38 | } | 52 | } |
| @@ -54,7 +68,7 @@ | |||
| 54 | aspect-ratio: 1 / 1; | 68 | aspect-ratio: 1 / 1; |
| 55 | font-size: 20px; | 69 | font-size: 20px; |
| 56 | opacity: 0.5; | 70 | opacity: 0.5; |
| 57 | transition: all 250ms; | 71 | transition: all var(--animation-duration-2x); |
| 58 | } | 72 | } |
| 59 | } | 73 | } |
| 60 | } | 74 | } |
| @@ -68,17 +82,21 @@ | |||
| 68 | #qr--popout>.qr--body { | 82 | #qr--popout>.qr--body { |
| 69 | >.qr--buttons { | 83 | >.qr--buttons { |
| 70 | --qr--color: transparent; | 84 | --qr--color: transparent; |
| 85 | |||
| 71 | &.qr--color { | 86 | &.qr--color { |
| 72 | background-color: var(--qr--color); | 87 | background-color: var(--qr--color); |
| 73 | } | 88 | } |
| 89 | |||
| 74 | &.qr--borderColor { | 90 | &.qr--borderColor { |
| 75 | background-color: transparent; | 91 | background-color: transparent; |
| 76 | border-left: 5px solid var(--qr--color); | 92 | border-left: 5px solid var(--qr--color); |
| 77 | border-right: 5px solid var(--qr--color); | 93 | border-right: 5px solid var(--qr--color); |
| 78 | } | 94 | } |
| 95 | |||
| 79 | &:has(.qr--buttons.qr--color) { | 96 | &:has(.qr--buttons.qr--color) { |
| 80 | margin: 5px; | 97 | margin: 5px; |
| 81 | } | 98 | } |
| 99 | |||
| 82 | margin: 0; | 100 | margin: 0; |
| 83 | padding: 0; | 101 | padding: 0; |
| 84 | display: flex; | 102 | display: flex; |
| @@ -89,6 +107,7 @@ | |||
| 89 | 107 | ||
| 90 | >.qr--buttons { | 108 | >.qr--buttons { |
| 91 | display: contents; | 109 | display: contents; |
| 110 | |||
| 92 | &.qr--color { | 111 | &.qr--color { |
| 93 | .qr--button:before { | 112 | .qr--button:before { |
| 94 | content: ''; | 113 | content: ''; |
| @@ -97,11 +116,14 @@ | |||
| 97 | inset: -5px; | 116 | inset: -5px; |
| 98 | z-index: -1; | 117 | z-index: -1; |
| 99 | } | 118 | } |
| 119 | |||
| 100 | &.qr--borderColor { | 120 | &.qr--borderColor { |
| 101 | .qr--button:before { | 121 | .qr--button:before { |
| 102 | display: none; | 122 | display: none; |
| 103 | } | 123 | } |
| 104 | &:before, &:after { | 124 | |
| 125 | &:before, | ||
| 126 | &:after { | ||
| 105 | content: ''; | 127 | content: ''; |
| 106 | width: 5px; | 128 | width: 5px; |
| 107 | background-color: var(--qr--color); | 129 | background-color: var(--qr--color); |
| @@ -118,7 +140,7 @@ | |||
| 118 | padding: 3px 5px; | 140 | padding: 3px 5px; |
| 119 | margin: 3px 0; | 141 | margin: 3px 0; |
| 120 | cursor: pointer; | 142 | cursor: pointer; |
| 121 | transition: 0.3s; | 143 | transition: var(--animation-duration-2x); |
| 122 | display: flex; | 144 | display: flex; |
| 123 | align-items: center; | 145 | align-items: center; |
| 124 | justify-content: center; | 146 | justify-content: center; |
| @@ -132,6 +154,7 @@ | |||
| 132 | .qr--hidden { | 154 | .qr--hidden { |
| 133 | display: none; | 155 | display: none; |
| 134 | } | 156 | } |
| 157 | |||
| 135 | .qr--button-icon { | 158 | .qr--button-icon { |
| 136 | margin: 0 0.5em; | 159 | margin: 0 0.5em; |
| 137 | } | 160 | } |
| @@ -274,18 +297,22 @@ | |||
| 274 | display: flex; | 297 | display: flex; |
| 275 | align-items: center; | 298 | align-items: center; |
| 276 | opacity: 0; | 299 | opacity: 0; |
| 277 | transition: 100ms; | 300 | transition: var(--animation-duration); |
| 278 | margin: -2px 0 -11px 0; | 301 | margin: -2px 0 -11px 0; |
| 279 | position: relative; | 302 | position: relative; |
| 303 | |||
| 280 | .qr--actions { | 304 | .qr--actions { |
| 281 | display: flex; | 305 | display: flex; |
| 282 | gap: 0.25em; | 306 | gap: 0.25em; |
| 283 | flex: 0 0 auto; | 307 | flex: 0 0 auto; |
| 308 | |||
| 284 | .qr--action { | 309 | .qr--action { |
| 285 | margin: 0; | 310 | margin: 0; |
| 286 | } | 311 | } |
| 287 | } | 312 | } |
| 288 | &:before, &:after { | 313 | |
| 314 | &:before, | ||
| 315 | &:after { | ||
| 289 | content: ""; | 316 | content: ""; |
| 290 | display: block; | 317 | display: block; |
| 291 | flex: 1 1 auto; | 318 | flex: 1 1 auto; |
| @@ -293,10 +320,13 @@ | |||
| 293 | margin: 0 1em; | 320 | margin: 0 1em; |
| 294 | height: 0; | 321 | height: 0; |
| 295 | } | 322 | } |
| 296 | &:hover, &:focus-within { | 323 | |
| 324 | &:hover, | ||
| 325 | &:focus-within { | ||
| 297 | opacity: 1; | 326 | opacity: 1; |
| 298 | } | 327 | } |
| 299 | } | 328 | } |
| 329 | |||
| 300 | >.qr--set-item .qr--content { | 330 | >.qr--set-item .qr--content { |
| 301 | display: flex; | 331 | display: flex; |
| 302 | flex-direction: row; | 332 | flex-direction: row; |
| @@ -336,9 +366,11 @@ | |||
| 336 | display: flex; | 366 | display: flex; |
| 337 | align-items: center; | 367 | align-items: center; |
| 338 | gap: 0.5em; | 368 | gap: 0.5em; |
| 369 | |||
| 339 | .qr--set-itemIcon:not(.fa-solid) { | 370 | .qr--set-itemIcon:not(.fa-solid) { |
| 340 | display: none; | 371 | display: none; |
| 341 | } | 372 | } |
| 373 | |||
| 342 | .qr--set-itemLabel { | 374 | .qr--set-itemLabel { |
| 343 | min-width: 24px; | 375 | min-width: 24px; |
| 344 | } | 376 | } |
| @@ -384,15 +416,16 @@ | |||
| 384 | align-items: baseline; | 416 | align-items: baseline; |
| 385 | } | 417 | } |
| 386 | } | 418 | } |
| 387 | >#qr--autoExec { | ||
| 388 | .checkbox_label { | ||
| 389 | text-wrap: nowrap; | ||
| 390 | 419 | ||
| 391 | .fa-fw { | 420 | >#qr--autoExec { |
| 392 | margin-right: 2px; | 421 | .checkbox_label { |
| 393 | } | 422 | text-wrap: nowrap; |
| 423 | |||
| 424 | .fa-fw { | ||
| 425 | margin-right: 2px; | ||
| 394 | } | 426 | } |
| 395 | } | 427 | } |
| 428 | } | ||
| 396 | } | 429 | } |
| 397 | 430 | ||
| 398 | 431 | ||
| @@ -433,65 +466,75 @@ | |||
| 433 | bottom: unset; | 466 | bottom: unset; |
| 434 | margin: unset; | 467 | margin: unset; |
| 435 | padding: 0; | 468 | padding: 0; |
| 469 | |||
| 436 | &::backdrop { | 470 | &::backdrop { |
| 437 | backdrop-filter: unset; | 471 | backdrop-filter: unset; |
| 438 | background-color: transparent; | 472 | background-color: transparent; |
| 439 | } | 473 | } |
| 474 | |||
| 440 | .popup-body { | 475 | .popup-body { |
| 441 | flex: 0 0 auto; | 476 | flex: 0 0 auto; |
| 442 | height: min-content; | 477 | height: min-content; |
| 443 | width: min-content; | 478 | width: min-content; |
| 444 | } | 479 | } |
| 480 | |||
| 445 | .popup-content { | 481 | .popup-content { |
| 446 | flex: 0 0 auto; | 482 | flex: 0 0 auto; |
| 447 | margin-top: 0; | 483 | margin-top: 0; |
| 448 | 484 | ||
| 449 | > #qr--modalEditor { | 485 | >#qr--modalEditor { |
| 450 | max-height: 50vh; | 486 | max-height: 50vh; |
| 451 | > #qr--main, | 487 | |
| 452 | > #qr--resizeHandle, | 488 | >#qr--main, |
| 453 | > #qr--qrOptions > h3, | 489 | >#qr--resizeHandle, |
| 454 | > #qr--qrOptions > #qr--modal-executeButtons, | 490 | >#qr--qrOptions>h3, |
| 455 | > #qr--qrOptions > #qr--modal-executeProgress | 491 | >#qr--qrOptions>#qr--modal-executeButtons, |
| 456 | { | 492 | >#qr--qrOptions>#qr--modal-executeProgress { |
| 457 | display: none; | 493 | display: none; |
| 458 | } | 494 | } |
| 495 | |||
| 459 | #qr--qrOptions { | 496 | #qr--qrOptions { |
| 460 | width: auto; | 497 | width: auto; |
| 461 | } | 498 | } |
| 499 | |||
| 462 | #qr--modal-debugButtons .qr--modal-debugButton#qr--modal-maximize { | 500 | #qr--modal-debugButtons .qr--modal-debugButton#qr--modal-maximize { |
| 463 | display: flex; | 501 | display: flex; |
| 464 | } | 502 | } |
| 503 | |||
| 465 | #qr--modal-debugButtons .qr--modal-debugButton#qr--modal-minimize { | 504 | #qr--modal-debugButtons .qr--modal-debugButton#qr--modal-minimize { |
| 466 | display: none; | 505 | display: none; |
| 467 | } | 506 | } |
| 507 | |||
| 468 | #qr--modal-debugState { | 508 | #qr--modal-debugState { |
| 469 | padding-top: 0; | 509 | padding-top: 0; |
| 470 | } | 510 | } |
| 471 | } | 511 | } |
| 472 | } | 512 | } |
| 473 | } | 513 | } |
| 474 | &:has(.qr--isExecuting) { | 514 | |
| 475 | .popup-controls { | 515 | &:has(.qr--isExecuting) { |
| 476 | display: none; | 516 | .popup-controls { |
| 477 | } | 517 | display: none; |
| 478 | 518 | } | |
| 479 | .qr--highlight { | 519 | |
| 480 | position: absolute; | 520 | .qr--highlight { |
| 481 | z-index: 50000; | 521 | position: absolute; |
| 482 | pointer-events: none; | 522 | z-index: 50000; |
| 483 | background-color: rgb(47 150 180 / 0.5); | 523 | pointer-events: none; |
| 484 | &.qr--unresolved { | 524 | background-color: rgb(47 150 180 / 0.5); |
| 485 | background-color: rgb(255 255 0 / 0.5); | 525 | |
| 486 | } | 526 | &.qr--unresolved { |
| 487 | } | 527 | background-color: rgb(255 255 0 / 0.5); |
| 488 | .qr--highlight-secondary { | 528 | } |
| 489 | position: absolute; | 529 | } |
| 490 | z-index: 50000; | 530 | |
| 491 | pointer-events: none; | 531 | .qr--highlight-secondary { |
| 492 | border: 3px solid red; | 532 | position: absolute; |
| 493 | } | 533 | z-index: 50000; |
| 494 | } | 534 | pointer-events: none; |
| 535 | border: 3px solid red; | ||
| 536 | } | ||
| 537 | } | ||
| 495 | 538 | ||
| 496 | .popup-content { | 539 | .popup-content { |
| 497 | display: flex; | 540 | display: flex; |
| @@ -504,36 +547,41 @@ | |||
| 504 | gap: 1em; | 547 | gap: 1em; |
| 505 | overflow: hidden; | 548 | overflow: hidden; |
| 506 | 549 | ||
| 507 | &.qr--isExecuting { | 550 | &.qr--isExecuting { |
| 508 | #qr--main > h3:first-child, | 551 | |
| 509 | #qr--main > .qr--labels, | 552 | #qr--main>h3:first-child, |
| 510 | #qr--main > .qr--modal-messageContainer > .qr--modal-editorSettings, | 553 | #qr--main>.qr--labels, |
| 511 | #qr--qrOptions > h3:first-child, | 554 | #qr--main>.qr--modal-messageContainer>.qr--modal-editorSettings, |
| 512 | #qr--qrOptions > #qr--ctxEditor, | 555 | #qr--qrOptions>h3:first-child, |
| 513 | #qr--qrOptions > .qr--ctxEditorActions, | 556 | #qr--qrOptions>#qr--ctxEditor, |
| 514 | #qr--qrOptions > .qr--ctxEditorActions + h3, | 557 | #qr--qrOptions>.qr--ctxEditorActions, |
| 515 | #qr--qrOptions > .qr--ctxEditorActions + h3 + div | 558 | #qr--qrOptions>.qr--ctxEditorActions+h3, |
| 516 | { | 559 | #qr--qrOptions>.qr--ctxEditorActions+h3+div { |
| 517 | display: none; | 560 | display: none; |
| 518 | } | 561 | } |
| 519 | #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder > #qr--modal-message { | 562 | |
| 520 | visibility: hidden; | 563 | #qr--main>.qr--modal-messageContainer>#qr--modal-messageHolder>#qr--modal-message { |
| 521 | } | 564 | visibility: hidden; |
| 522 | #qr--modal-debugButtons { | 565 | } |
| 523 | display: flex; | 566 | |
| 567 | #qr--modal-debugButtons { | ||
| 568 | display: flex; | ||
| 569 | |||
| 524 | .menu_button:not(#qr--modal-minimize, #qr--modal-maximize) { | 570 | .menu_button:not(#qr--modal-minimize, #qr--modal-maximize) { |
| 525 | cursor: not-allowed; | 571 | cursor: not-allowed; |
| 526 | opacity: 0.5; | 572 | opacity: 0.5; |
| 527 | pointer-events: none; | 573 | pointer-events: none; |
| 528 | transition: 200ms; | 574 | transition: var(--animation-duration-2x); |
| 529 | border-color: transparent; | 575 | border-color: transparent; |
| 530 | } | 576 | } |
| 531 | } | 577 | } |
| 578 | |||
| 532 | &.qr--isPaused #qr--modal-debugButtons { | 579 | &.qr--isPaused #qr--modal-debugButtons { |
| 533 | .menu_button:not(#qr--modal-minimize, #qr--modal-maximize) { | 580 | .menu_button:not(#qr--modal-minimize, #qr--modal-maximize) { |
| 534 | cursor: pointer; | 581 | cursor: pointer; |
| 535 | opacity: 1; | 582 | opacity: 1; |
| 536 | pointer-events: all; | 583 | pointer-events: all; |
| 584 | |||
| 537 | &#qr--modal-resume { | 585 | &#qr--modal-resume { |
| 538 | animation-name: qr--debugPulse; | 586 | animation-name: qr--debugPulse; |
| 539 | animation-duration: 1500ms; | 587 | animation-duration: 1500ms; |
| @@ -541,73 +589,90 @@ | |||
| 541 | animation-delay: 0s; | 589 | animation-delay: 0s; |
| 542 | animation-iteration-count: infinite; | 590 | animation-iteration-count: infinite; |
| 543 | } | 591 | } |
| 592 | |||
| 544 | &#qr--modal-resume { | 593 | &#qr--modal-resume { |
| 545 | border-color: rgb(81, 163, 81); | 594 | border-color: rgb(81, 163, 81); |
| 546 | } | 595 | } |
| 596 | |||
| 547 | &#qr--modal-step { | 597 | &#qr--modal-step { |
| 548 | border-color: var(--SmartThemeQuoteColor); | 598 | border-color: var(--SmartThemeQuoteColor); |
| 549 | } | 599 | } |
| 600 | |||
| 550 | &#qr--modal-stepInto { | 601 | &#qr--modal-stepInto { |
| 551 | border-color: var(--SmartThemeQuoteColor); | 602 | border-color: var(--SmartThemeQuoteColor); |
| 552 | } | 603 | } |
| 604 | |||
| 553 | &#qr--modal-stepOut { | 605 | &#qr--modal-stepOut { |
| 554 | border-color: var(--SmartThemeQuoteColor); | 606 | border-color: var(--SmartThemeQuoteColor); |
| 555 | } | 607 | } |
| 556 | } | 608 | } |
| 557 | } | 609 | } |
| 558 | #qr--resizeHandle { | 610 | |
| 559 | width: 6px; | 611 | #qr--resizeHandle { |
| 560 | background-color: var(--SmartThemeBorderColor); | 612 | width: 6px; |
| 561 | border: 2px solid var(--SmartThemeBlurTintColor); | 613 | background-color: var(--SmartThemeBorderColor); |
| 562 | transition: border-color 200ms, background-color 200ms; | 614 | border: 2px solid var(--SmartThemeBlurTintColor); |
| 563 | cursor: w-resize; | 615 | transition: border-color var(--animation-duration-2x), background-color var(--animation-duration-2x); |
| 564 | &:hover { | 616 | cursor: w-resize; |
| 565 | background-color: var(--SmartThemeQuoteColor); | 617 | |
| 566 | border-color: var(--SmartThemeQuoteColor); | 618 | &:hover { |
| 567 | } | 619 | background-color: var(--SmartThemeQuoteColor); |
| 568 | } | 620 | border-color: var(--SmartThemeQuoteColor); |
| 569 | #qr--qrOptions { | 621 | } |
| 570 | width: var(--width, auto); | 622 | } |
| 571 | } | 623 | |
| 572 | } | 624 | #qr--qrOptions { |
| 573 | 625 | width: var(--width, auto); | |
| 574 | > #qr--main { | 626 | } |
| 575 | flex: 1 1 auto; | 627 | } |
| 576 | display: flex; | 628 | |
| 577 | flex-direction: column; | 629 | >#qr--main { |
| 578 | overflow: hidden; | 630 | flex: 1 1 auto; |
| 579 | > .qr--labels { | 631 | display: flex; |
| 580 | flex: 0 0 auto; | 632 | flex-direction: column; |
| 581 | display: flex; | 633 | overflow: hidden; |
| 582 | flex-direction: row; | 634 | |
| 583 | gap: 0.5em; | 635 | >.qr--labels { |
| 584 | padding: 1px; | 636 | flex: 0 0 auto; |
| 585 | > label, > .label { | 637 | display: flex; |
| 586 | flex: 1 1 1px; | 638 | flex-direction: row; |
| 587 | display: flex; | 639 | gap: 0.5em; |
| 588 | flex-direction: column; | 640 | padding: 1px; |
| 641 | |||
| 642 | >label, | ||
| 643 | >.label { | ||
| 644 | flex: 1 1 1px; | ||
| 645 | display: flex; | ||
| 646 | flex-direction: column; | ||
| 589 | position: relative; | 647 | position: relative; |
| 648 | |||
| 590 | &.qr--fit { | 649 | &.qr--fit { |
| 591 | flex: 0 0 auto; | 650 | flex: 0 0 auto; |
| 592 | justify-content: center; | 651 | justify-content: center; |
| 593 | } | 652 | } |
| 653 | |||
| 594 | .qr--inputGroup { | 654 | .qr--inputGroup { |
| 595 | display: flex; | 655 | display: flex; |
| 596 | align-items: baseline; | 656 | align-items: baseline; |
| 597 | gap: 0.5em; | 657 | gap: 0.5em; |
| 658 | |||
| 598 | input { | 659 | input { |
| 599 | flex: 1 1 auto; | 660 | flex: 1 1 auto; |
| 600 | } | 661 | } |
| 601 | } | 662 | } |
| 602 | .qr--labelText { | 663 | |
| 603 | flex: 1 1 auto; | 664 | .qr--labelText { |
| 604 | } | 665 | flex: 1 1 auto; |
| 605 | .qr--labelHint { | 666 | } |
| 606 | flex: 1 1 auto; | 667 | |
| 607 | } | 668 | .qr--labelHint { |
| 608 | input { | 669 | flex: 1 1 auto; |
| 609 | flex: 0 0 auto; | 670 | } |
| 610 | } | 671 | |
| 672 | input { | ||
| 673 | flex: 0 0 auto; | ||
| 674 | } | ||
| 675 | |||
| 611 | .qr--modal-switcherList { | 676 | .qr--modal-switcherList { |
| 612 | background-color: var(--stcdx--bgColor); | 677 | background-color: var(--stcdx--bgColor); |
| 613 | border: 1px solid var(--SmartThemeBorderColor); | 678 | border: 1px solid var(--SmartThemeBorderColor); |
| @@ -625,25 +690,32 @@ | |||
| 625 | list-style: none; | 690 | list-style: none; |
| 626 | z-index: 40000; | 691 | z-index: 40000; |
| 627 | max-width: 100%; | 692 | max-width: 100%; |
| 693 | |||
| 628 | .qr--modal-switcherItem { | 694 | .qr--modal-switcherItem { |
| 629 | display: flex; | 695 | display: flex; |
| 630 | gap: 1em; | 696 | gap: 1em; |
| 631 | text-align: left; | 697 | text-align: left; |
| 632 | opacity: 0.75; | 698 | opacity: 0.75; |
| 633 | transition: 200ms; | 699 | transition: var(--animation-duration-2x); |
| 634 | cursor: pointer; | 700 | cursor: pointer; |
| 701 | |||
| 635 | &:hover { | 702 | &:hover { |
| 636 | opacity: 1; | 703 | opacity: 1; |
| 637 | } | 704 | } |
| 705 | |||
| 638 | &.qr--current { | 706 | &.qr--current { |
| 639 | opacity: 1; | 707 | opacity: 1; |
| 640 | .qr--label, .qr--id { | 708 | |
| 709 | .qr--label, | ||
| 710 | .qr--id { | ||
| 641 | font-weight: bold; | 711 | font-weight: bold; |
| 642 | } | 712 | } |
| 643 | } | 713 | } |
| 644 | } | 714 | } |
| 715 | |||
| 645 | .qr--label { | 716 | .qr--label { |
| 646 | white-space: nowrap; | 717 | white-space: nowrap; |
| 718 | |||
| 647 | .menu_button { | 719 | .menu_button { |
| 648 | display: inline-block; | 720 | display: inline-block; |
| 649 | height: min-content; | 721 | height: min-content; |
| @@ -651,11 +723,19 @@ | |||
| 651 | margin: 0 0.5em 0 0; | 723 | margin: 0 0.5em 0 0; |
| 652 | } | 724 | } |
| 653 | } | 725 | } |
| 726 | |||
| 654 | .qr--id { | 727 | .qr--id { |
| 655 | opacity: 0.5; | 728 | opacity: 0.5; |
| 656 | &:before { content: "["; } | 729 | |
| 657 | &:after { content: "]"; } | 730 | &:before { |
| 731 | content: "["; | ||
| 732 | } | ||
| 733 | |||
| 734 | &:after { | ||
| 735 | content: "]"; | ||
| 736 | } | ||
| 658 | } | 737 | } |
| 738 | |||
| 659 | .qr--message { | 739 | .qr--message { |
| 660 | height: 1lh; | 740 | height: 1lh; |
| 661 | overflow: hidden; | 741 | overflow: hidden; |
| @@ -664,102 +744,124 @@ | |||
| 664 | opacity: 0.5; | 744 | opacity: 0.5; |
| 665 | } | 745 | } |
| 666 | } | 746 | } |
| 667 | } | 747 | } |
| 668 | } | 748 | } |
| 669 | > .qr--modal-messageContainer { | 749 | |
| 670 | flex: 1 1 auto; | 750 | >.qr--modal-messageContainer { |
| 671 | display: flex; | 751 | flex: 1 1 auto; |
| 672 | flex-direction: column; | 752 | display: flex; |
| 673 | overflow: hidden; | 753 | flex-direction: column; |
| 674 | > .qr--modal-editorSettings { | 754 | overflow: hidden; |
| 675 | display: flex; | 755 | |
| 756 | >.qr--modal-editorSettings { | ||
| 757 | display: flex; | ||
| 676 | flex-wrap: wrap; | 758 | flex-wrap: wrap; |
| 677 | flex-direction: row; | 759 | flex-direction: row; |
| 678 | column-gap: 1em; | 760 | column-gap: 1em; |
| 679 | color: var(--grey70); | 761 | color: var(--grey70); |
| 680 | font-size: smaller; | 762 | font-size: smaller; |
| 681 | align-items: baseline; | 763 | align-items: baseline; |
| 682 | > .checkbox_label { | 764 | |
| 683 | white-space: nowrap; | 765 | >.checkbox_label { |
| 684 | > input { | 766 | white-space: nowrap; |
| 685 | font-size: inherit; | 767 | |
| 686 | } | 768 | >input { |
| 687 | } | 769 | font-size: inherit; |
| 688 | } | 770 | } |
| 689 | > #qr--modal-messageHolder { | 771 | } |
| 690 | flex: 1 1 auto; | 772 | } |
| 691 | display: grid; | 773 | |
| 692 | text-align: left; | 774 | >#qr--modal-messageHolder { |
| 693 | overflow: hidden; | 775 | flex: 1 1 auto; |
| 694 | &.qr--noSyntax { | 776 | display: grid; |
| 695 | > #qr--modal-messageSyntax { | 777 | text-align: left; |
| 696 | display: none; | 778 | overflow: hidden; |
| 697 | } | 779 | |
| 698 | > #qr--modal-message { | 780 | &.qr--noSyntax { |
| 699 | background-color: var(--ac-style-color-background); | 781 | >#qr--modal-messageSyntax { |
| 700 | color: var(--ac-style-color-text); | 782 | display: none; |
| 701 | &::-webkit-scrollbar, &::-webkit-scrollbar-thumb { | 783 | } |
| 784 | |||
| 785 | >#qr--modal-message { | ||
| 786 | background-color: var(--ac-style-color-background); | ||
| 787 | color: var(--ac-style-color-text); | ||
| 788 | |||
| 789 | &::-webkit-scrollbar, | ||
| 790 | &::-webkit-scrollbar-thumb { | ||
| 702 | visibility: visible; | 791 | visibility: visible; |
| 703 | cursor: unset; | 792 | cursor: unset; |
| 704 | } | 793 | } |
| 705 | &::selection { | 794 | |
| 706 | color: unset; | 795 | &::selection { |
| 707 | background-color: rgba(108 171 251 / 0.25); | 796 | color: unset; |
| 708 | @supports (color: rgb(from white r g b / 0.25)) { | 797 | background-color: rgba(108 171 251 / 0.25); |
| 709 | background-color: rgb(from var(--ac-style-color-matchedText) r g b / 0.25); | 798 | |
| 710 | } | 799 | @supports (color: rgb(from white r g b / 0.25)) { |
| 711 | } | 800 | background-color: rgb(from var(--ac-style-color-matchedText) r g b / 0.25); |
| 712 | } | 801 | } |
| 713 | } | 802 | } |
| 714 | > #qr--modal-messageSyntax { | 803 | } |
| 715 | grid-column: 1; | 804 | } |
| 716 | grid-row: 1; | 805 | |
| 717 | padding: 0; | 806 | >#qr--modal-messageSyntax { |
| 718 | margin: 0; | 807 | grid-column: 1; |
| 719 | border: none; | 808 | grid-row: 1; |
| 720 | overflow: hidden; | 809 | padding: 0; |
| 721 | min-width: 100%; | 810 | margin: 0; |
| 722 | width: 0; | 811 | border: none; |
| 723 | > #qr--modal-messageSyntaxInner { | 812 | overflow: hidden; |
| 724 | height: 100%; | 813 | min-width: 100%; |
| 725 | } | 814 | width: 0; |
| 726 | } | 815 | |
| 727 | > #qr--modal-message { | 816 | >#qr--modal-messageSyntaxInner { |
| 728 | background-color: transparent; | 817 | height: 100%; |
| 729 | color: transparent; | 818 | } |
| 730 | grid-column: 1; | 819 | } |
| 731 | grid-row: 1; | 820 | |
| 732 | caret-color: var(--ac-style-color-text); | 821 | >#qr--modal-message { |
| 733 | overflow: auto; | 822 | background-color: transparent; |
| 734 | &::-webkit-scrollbar, &::-webkit-scrollbar-thumb { | 823 | color: transparent; |
| 735 | visibility: hidden; | 824 | grid-column: 1; |
| 736 | cursor: default; | 825 | grid-row: 1; |
| 737 | } | 826 | caret-color: var(--ac-style-color-text); |
| 738 | &::selection { | 827 | overflow: auto; |
| 739 | color: transparent; | 828 | |
| 740 | background-color: rgba(108 171 251 / 0.25); | 829 | &::-webkit-scrollbar, |
| 741 | @supports (color: rgb(from white r g b / 0.25)) { | 830 | &::-webkit-scrollbar-thumb { |
| 742 | background-color: rgb(from var(--ac-style-color-matchedText) r g b / 0.25); | 831 | visibility: hidden; |
| 743 | } | 832 | cursor: default; |
| 744 | } | 833 | } |
| 745 | } | 834 | |
| 746 | #qr--modal-message, #qr--modal-messageSyntaxInner { | 835 | &::selection { |
| 747 | font-family: var(--monoFontFamily); | 836 | color: transparent; |
| 748 | padding: 0.75em; | 837 | background-color: rgba(108 171 251 / 0.25); |
| 749 | margin: 0; | 838 | |
| 750 | resize: none; | 839 | @supports (color: rgb(from white r g b / 0.25)) { |
| 751 | line-height: 1.2; | 840 | background-color: rgb(from var(--ac-style-color-matchedText) r g b / 0.25); |
| 752 | border: 1px solid var(--SmartThemeBorderColor); | 841 | } |
| 753 | border-radius: 5px; | 842 | } |
| 754 | position: relative; | 843 | } |
| 755 | } | 844 | |
| 756 | } | 845 | #qr--modal-message, |
| 757 | } | 846 | #qr--modal-messageSyntaxInner { |
| 758 | } | 847 | font-family: var(--monoFontFamily); |
| 848 | padding: 0.75em; | ||
| 849 | margin: 0; | ||
| 850 | resize: none; | ||
| 851 | line-height: 1.2; | ||
| 852 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 853 | border-radius: 5px; | ||
| 854 | position: relative; | ||
| 855 | } | ||
| 856 | } | ||
| 857 | } | ||
| 858 | } | ||
| 859 | |||
| 759 | #qr--modal-icon { | 860 | #qr--modal-icon { |
| 760 | height: 100%; | 861 | height: 100%; |
| 761 | aspect-ratio: 1 / 1; | 862 | aspect-ratio: 1 / 1; |
| 762 | } | 863 | } |
| 864 | |||
| 763 | #qr--modal-executeButtons { | 865 | #qr--modal-executeButtons { |
| 764 | display: flex; | 866 | display: flex; |
| 765 | gap: 1em; | 867 | gap: 1em; |
| @@ -778,7 +880,7 @@ | |||
| 778 | } | 880 | } |
| 779 | 881 | ||
| 780 | #qr--modal-execute { | 882 | #qr--modal-execute { |
| 781 | transition: 200ms; | 883 | transition: var(--animation-duration-2x); |
| 782 | filter: grayscale(0); | 884 | filter: grayscale(0); |
| 783 | 885 | ||
| 784 | &.qr--busy { | 886 | &.qr--busy { |
| @@ -819,16 +921,20 @@ | |||
| 819 | border-color: rgb(215, 136, 114); | 921 | border-color: rgb(215, 136, 114); |
| 820 | } | 922 | } |
| 821 | } | 923 | } |
| 822 | #qr--modal-debugButtons { | 924 | |
| 823 | display: none; | 925 | #qr--modal-debugButtons { |
| 824 | gap: 1em; | 926 | display: none; |
| 825 | .qr--modal-debugButton { | 927 | gap: 1em; |
| 826 | aspect-ratio: 1.25 / 1; | 928 | |
| 827 | width: 2.25em; | 929 | .qr--modal-debugButton { |
| 930 | aspect-ratio: 1.25 / 1; | ||
| 931 | width: 2.25em; | ||
| 828 | position: relative; | 932 | position: relative; |
| 933 | |||
| 829 | &:not(.fa-solid) { | 934 | &:not(.fa-solid) { |
| 830 | border-width: 1px; | 935 | border-width: 1px; |
| 831 | border-style: solid; | 936 | border-style: solid; |
| 937 | |||
| 832 | &:after { | 938 | &:after { |
| 833 | content: ''; | 939 | content: ''; |
| 834 | position: absolute; | 940 | position: absolute; |
| @@ -839,23 +945,28 @@ | |||
| 839 | mask-repeat: no-repeat; | 945 | mask-repeat: no-repeat; |
| 840 | } | 946 | } |
| 841 | } | 947 | } |
| 948 | |||
| 842 | &#qr--modal-resume:after { | 949 | &#qr--modal-resume:after { |
| 843 | mask-image: url('/img/step-resume.svg'); | 950 | mask-image: url('/img/step-resume.svg'); |
| 844 | } | 951 | } |
| 952 | |||
| 845 | &#qr--modal-step:after { | 953 | &#qr--modal-step:after { |
| 846 | mask-image: url('/img/step-over.svg'); | 954 | mask-image: url('/img/step-over.svg'); |
| 847 | } | 955 | } |
| 956 | |||
| 848 | &#qr--modal-stepInto:after { | 957 | &#qr--modal-stepInto:after { |
| 849 | mask-image: url('/img/step-into.svg'); | 958 | mask-image: url('/img/step-into.svg'); |
| 850 | } | 959 | } |
| 960 | |||
| 851 | &#qr--modal-stepOut:after { | 961 | &#qr--modal-stepOut:after { |
| 852 | mask-image: url('/img/step-out.svg'); | 962 | mask-image: url('/img/step-out.svg'); |
| 853 | } | 963 | } |
| 964 | |||
| 854 | &#qr--modal-maximize { | 965 | &#qr--modal-maximize { |
| 855 | display: none; | 966 | display: none; |
| 856 | } | 967 | } |
| 857 | } | 968 | } |
| 858 | } | 969 | } |
| 859 | 970 | ||
| 860 | #qr--modal-send_textarea { | 971 | #qr--modal-send_textarea { |
| 861 | flex: 0 0 auto; | 972 | flex: 0 0 auto; |
| @@ -879,7 +990,7 @@ | |||
| 879 | position: absolute; | 990 | position: absolute; |
| 880 | inset: 0; | 991 | inset: 0; |
| 881 | right: calc(100% - var(--prog) * 1%); | 992 | right: calc(100% - var(--prog) * 1%); |
| 882 | transition: 200ms; | 993 | transition: var(--animation-duration-2x); |
| 883 | } | 994 | } |
| 884 | 995 | ||
| 885 | &.qr--paused:after { | 996 | &.qr--paused:after { |
| @@ -939,135 +1050,180 @@ | |||
| 939 | overflow: auto; | 1050 | overflow: auto; |
| 940 | min-width: 100%; | 1051 | min-width: 100%; |
| 941 | width: 0; | 1052 | width: 0; |
| 942 | white-space: pre-wrap; | 1053 | white-space: pre-wrap; |
| 943 | } | 1054 | } |
| 944 | #qr--modal-debugState { | 1055 | |
| 945 | display: none; | 1056 | #qr--modal-debugState { |
| 946 | &.qr--active { | 1057 | display: none; |
| 947 | display: block; | 1058 | |
| 948 | } | 1059 | &.qr--active { |
| 949 | text-align: left; | 1060 | display: block; |
| 950 | font-size: smaller; | 1061 | } |
| 951 | font-family: var(--monoFontFamily); | 1062 | |
| 952 | // background-color: rgb(146, 190, 252); | 1063 | text-align: left; |
| 953 | color: white; | 1064 | font-size: smaller; |
| 954 | padding: 0.5em 0; | 1065 | font-family: var(--monoFontFamily); |
| 955 | overflow: auto; | 1066 | // background-color: rgb(146, 190, 252); |
| 956 | min-width: 100%; | 1067 | color: white; |
| 957 | width: 0; | 1068 | padding: 0.5em 0; |
| 958 | white-space: pre-wrap; | 1069 | overflow: auto; |
| 959 | 1070 | min-width: 100%; | |
| 960 | .qr--scope { | 1071 | width: 0; |
| 961 | display: grid; | 1072 | white-space: pre-wrap; |
| 962 | grid-template-columns: 0fr 1fr 1fr; | 1073 | |
| 963 | column-gap: 0em; | 1074 | .qr--scope { |
| 964 | .qr--title { | 1075 | display: grid; |
| 965 | grid-column: 1 / 4; | 1076 | grid-template-columns: 0fr 1fr 1fr; |
| 966 | font-weight: bold; | 1077 | column-gap: 0em; |
| 967 | font-family: var(--mainFontFamily); | 1078 | |
| 968 | background-color: var(--black50a); | 1079 | .qr--title { |
| 969 | padding: 0.25em; | 1080 | grid-column: 1 / 4; |
| 970 | margin-top: 0.5em; | 1081 | font-weight: bold; |
| 971 | } | 1082 | font-family: var(--mainFontFamily); |
| 972 | .qr--var, .qr--macro, .qr--pipe { | 1083 | background-color: var(--black50a); |
| 973 | display: contents; | 1084 | padding: 0.25em; |
| 974 | &:nth-child(2n + 1) { | 1085 | margin-top: 0.5em; |
| 975 | .qr--key, .qr--val { | 1086 | } |
| 976 | background-color: rgb(from var(--SmartThemeEmColor) r g b / 0.25); | 1087 | |
| 977 | } | 1088 | .qr--var, |
| 978 | .qr--val { | 1089 | .qr--macro, |
| 979 | &:nth-child(2n) { | 1090 | .qr--pipe { |
| 980 | background-color: rgb(from var(--SmartThemeEmColor) r g b / 0.125); | 1091 | display: contents; |
| 981 | } | 1092 | |
| 982 | &:hover { | 1093 | &:nth-child(2n + 1) { |
| 983 | background-color: rgb(from var(--SmartThemeEmColor) r g b / 0.5); | 1094 | |
| 984 | } | 1095 | .qr--key, |
| 985 | } | 1096 | .qr--val { |
| 986 | } | 1097 | background-color: rgb(from var(--SmartThemeEmColor) r g b / 0.25); |
| 987 | &:nth-child(2n) { | 1098 | } |
| 988 | .qr--val { | 1099 | |
| 989 | &:nth-child(2n) { | 1100 | .qr--val { |
| 990 | background-color: rgb(from var(--SmartThemeEmColor) r g b / 0.0625); | ||
| 991 | } | ||
| 992 | &:hover { | ||
| 993 | background-color: rgb(from var(--SmartThemeEmColor) r g b / 0.5); | ||
| 994 | } | ||
| 995 | } | ||
| 996 | } | ||
| 997 | &.qr--isHidden { | ||
| 998 | .qr--key, .qr--val { | ||
| 999 | opacity: 0.5; | ||
| 1000 | } | ||
| 1001 | } | ||
| 1002 | .qr--val { | ||
| 1003 | grid-column: 2 / 4; | ||
| 1004 | &.qr--singleCol { | ||
| 1005 | grid-column: unset; | ||
| 1006 | } | ||
| 1007 | &.qr--simple { | ||
| 1008 | &:before, &:after { | ||
| 1009 | content: '"'; | ||
| 1010 | color: var(--SmartThemeQuoteColor); | ||
| 1011 | } | ||
| 1012 | } | ||
| 1013 | &.qr--unresolved { | ||
| 1014 | &:after { | ||
| 1015 | content: '-UNRESOLVED-'; | ||
| 1016 | font-style: italic; | ||
| 1017 | color: var(--SmartThemeQuoteColor); | ||
| 1018 | } | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | } | ||
| 1022 | .qr--key { | ||
| 1023 | margin-left: 0.5em; | ||
| 1024 | padding-right: 1em; | ||
| 1025 | &:after { content: ": "; } | ||
| 1026 | } | ||
| 1027 | .qr--pipe, .qr--macro { | ||
| 1028 | > .qr--key { | ||
| 1029 | &:before { content: "{{"; } | ||
| 1030 | &:after { content: "}}: "; } | ||
| 1031 | } | ||
| 1032 | } | ||
| 1033 | .qr--scope { | ||
| 1034 | display: contents; | ||
| 1035 | .qr--pipe { | ||
| 1036 | .qr--key, .qr--val { | ||
| 1037 | opacity: 0.5; | ||
| 1038 | } | ||
| 1039 | } | ||
| 1040 | } | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | .qr--stack { | ||
Diff truncated