Merge branch 'parser-followup-2' of https://github.com/LenAnderson/SillyTavern into parser-followup-2

83ba31ba063caf2dd8e1d2d5f1f952e220f38e5c

LenAnderson <Anderson.Len@outlook.com>

25 files changed, +176 -211Ignore whitespace
public/css/tags.css+6 -6
@@ -209,20 +209,20 @@
209 opacity: 1;209 opacity: 1;
210}210}
211211
212.tag_as_folder {212.tag_as_folder.right_menu_button {
213 filter: brightness(75%) saturate(0.6);213 filter: brightness(75%) saturate(0.6);
214}214}
215215
216.tag_as_folder:hover,216.tag_as_folder.right_menu_button:hover,
217.tag_as_folder.flash {217.tag_as_folder.right_menu_button.flash {
218 filter: brightness(150%) saturate(0.6) !important;218 filter: brightness(150%) saturate(0.6);
219}219}
220220
221.tag_as_folder.no_folder {221.tag_as_folder.right_menu_button.no_folder {
222 filter: brightness(25%) saturate(0.25);222 filter: brightness(25%) saturate(0.25);
223}223}
224224
225.tag_as_folder .tag_folder_indicator {225.tag_as_folder.right_menu_button .tag_folder_indicator {
226 position: absolute;226 position: absolute;
227 top: calc(var(--mainFontSize) * -0.5);227 top: calc(var(--mainFontSize) * -0.5);
228 right: calc(var(--mainFontSize) * -0.5);228 right: calc(var(--mainFontSize) * -0.5);
public/index.html+6 -2
@@ -1544,7 +1544,7 @@
1544 <h4 class="wide100p textAlignCenter">1544 <h4 class="wide100p textAlignCenter">
1545 <label>1545 <label>
1546 <span data-i18n="Grammar String">Grammar String</span>1546 <span data-i18n="Grammar String">Grammar String</span>
1547 <div class="margin5 fa-solid fa-circle-info opacity50p " data-i18n="[title]GNBF or ENBF, depends on the backend in use. If you're using this you should know which." title="GNBF or ENBF, depends on the backend in use. If you're using this you should know which."></div>1547 <div class="margin5 fa-solid fa-circle-info opacity50p " data-i18n="[title]GBNF or EBNF, depends on the backend in use. If you're using this you should know which." title="GBNF or EBNF, depends on the backend in use. If you're using this you should know which."></div>
1548 <a href="https://github.com/ggerganov/llama.cpp/blob/master/grammars/README.md" target="_blank">1548 <a href="https://github.com/ggerganov/llama.cpp/blob/master/grammars/README.md" target="_blank">
1549 <small>1549 <small>
1550 <div class="fa-solid fa-up-right-from-square note-link-span"></div>1550 <div class="fa-solid fa-up-right-from-square note-link-span"></div>
@@ -3069,7 +3069,11 @@
3069 </div>3069 </div>
3070 <label class="checkbox_label" title="Add Chat Start and Example Separator to a list of stopping strings." data-i18n="[title]Add Chat Start and Example Separator to a list of stopping strings.">3070 <label class="checkbox_label" title="Add Chat Start and Example Separator to a list of stopping strings." data-i18n="[title]Add Chat Start and Example Separator to a list of stopping strings.">
3071 <input id="context_use_stop_strings" type="checkbox" />3071 <input id="context_use_stop_strings" type="checkbox" />
3072 <small data-i18n="Use as Stop Strings">Use as Stop Strings</small>3072 <small data-i18n="Separators as Stop Strings">Separators as Stop Strings</small>
3073 </label>
3074 <label class="checkbox_label" title="Add Character and User names to a list of stopping strings." data-i18n="[title]Add Character and User names to a list of stopping strings.">
3075 <input id="context_names_as_stop_strings" type="checkbox" />
3076 <small data-i18n="Names as Stop Strings">Names as Stop Strings</small>
3073 </label>3077 </label>
3074 <label class="checkbox_label" title="Includes Post-History Instructions at the end of the prompt, if defined in the character card AND ''Prefer Char. Instructions'' is enabled.&#10;THIS IS NOT RECOMMENDED FOR TEXT COMPLETION MODELS, CAN LEAD TO BAD OUTPUT." data-i18n="[title]context_allow_post_history_instructions">3078 <label class="checkbox_label" title="Includes Post-History Instructions at the end of the prompt, if defined in the character card AND ''Prefer Char. Instructions'' is enabled.&#10;THIS IS NOT RECOMMENDED FOR TEXT COMPLETION MODELS, CAN LEAD TO BAD OUTPUT." data-i18n="[title]context_allow_post_history_instructions">
3075 <input id="context_allow_jailbreak" type="checkbox" />3079 <input id="context_allow_jailbreak" type="checkbox" />
public/locales/ar-sa.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "مخطط جيسون",207 "JSON Schema": "مخطط جيسون",
208 "Type in the desired JSON schema": "اكتب مخطط JSON المطلوب",208 "Type in the desired JSON schema": "اكتب مخطط JSON المطلوب",
209 "Grammar String": "سلسلة القواعد",209 "Grammar String": "سلسلة القواعد",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "يعتمد GNBF أو ENBF على الواجهة الخلفية المستخدمة. إذا كنت تستخدم هذا يجب أن تعرف أي.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "يعتمد GBNF أو EBNF على الواجهة الخلفية المستخدمة. إذا كنت تستخدم هذا يجب أن تعرف أي.",
211 "Top P & Min P": "أعلى ع وأدنى ص",211 "Top P & Min P": "أعلى ع وأدنى ص",
212 "Load default order": "تحميل الترتيب الافتراضي",212 "Load default order": "تحميل الترتيب الافتراضي",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp فقط. تحديد ترتيب أخذ العينات. إذا لم يكن وضع Mirostat 0، فسيتم تجاهل ترتيب أخذ العينات.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp فقط. تحديد ترتيب أخذ العينات. إذا لم يكن وضع Mirostat 0، فسيتم تجاهل ترتيب أخذ العينات.",
public/locales/de-de.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "JSON-Schema",207 "JSON Schema": "JSON-Schema",
208 "Type in the desired JSON schema": "Geben Sie das gewünschte JSON-Schema ein",208 "Type in the desired JSON schema": "Geben Sie das gewünschte JSON-Schema ein",
209 "Grammar String": "Grammatikzeichenfolge",209 "Grammar String": "Grammatikzeichenfolge",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF oder ENBF, hängt vom verwendeten Backend ab. Wenn Sie dieses verwenden, sollten Sie wissen, welches.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF oder EBNF, hängt vom verwendeten Backend ab. Wenn Sie dieses verwenden, sollten Sie wissen, welches.",
211 "Top P & Min P": "Top P und Min P",211 "Top P & Min P": "Top P und Min P",
212 "Load default order": "Standardreihenfolge laden",212 "Load default order": "Standardreihenfolge laden",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "Nur llama.cpp. Bestimmt die Reihenfolge der Sampler. Wenn der Mirostat-Modus nicht 0 ist, wird die Sampler-Reihenfolge ignoriert.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "Nur llama.cpp. Bestimmt die Reihenfolge der Sampler. Wenn der Mirostat-Modus nicht 0 ist, wird die Sampler-Reihenfolge ignoriert.",
public/locales/es-es.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "Esquema JSON",207 "JSON Schema": "Esquema JSON",
208 "Type in the desired JSON schema": "Escriba el esquema JSON deseado",208 "Type in the desired JSON schema": "Escriba el esquema JSON deseado",
209 "Grammar String": "Cadena de gramática",209 "Grammar String": "Cadena de gramática",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF o ENBF, depende del backend en uso. Si estás usando esto, debes saber cuál.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF o EBNF, depende del backend en uso. Si estás usando esto, debes saber cuál.",
211 "Top P & Min P": "P superior y P mínima",211 "Top P & Min P": "P superior y P mínima",
212 "Load default order": "Cargar orden predeterminado",212 "Load default order": "Cargar orden predeterminado",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp únicamente. Determina el orden de los muestreadores. Si el modo Mirostat no es 0, se ignora el orden de las muestras.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp únicamente. Determina el orden de los muestreadores. Si el modo Mirostat no es 0, se ignora el orden de las muestras.",
public/locales/fr-fr.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "Schéma JSON",207 "JSON Schema": "Schéma JSON",
208 "Type in the desired JSON schema": "Tapez le schéma JSON souhaité",208 "Type in the desired JSON schema": "Tapez le schéma JSON souhaité",
209 "Grammar String": "Chaîne de grammaire",209 "Grammar String": "Chaîne de grammaire",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF ou ENBF dépend du backend utilisé. Si vous l'utilisez, vous devez savoir lequel.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF ou EBNF dépend du backend utilisé. Si vous l'utilisez, vous devez savoir lequel.",
211 "Top P & Min P": "P supérieur et P minimal",211 "Top P & Min P": "P supérieur et P minimal",
212 "Load default order": "Charger l'ordre par défaut",212 "Load default order": "Charger l'ordre par défaut",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "lama.cpp uniquement. Détermine l’ordre des échantillonneurs. Si le mode Mirostat n'est pas 0, l'ordre de l'échantillonneur est ignoré.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "lama.cpp uniquement. Détermine l’ordre des échantillonneurs. Si le mode Mirostat n'est pas 0, l'ordre de l'échantillonneur est ignoré.",
public/locales/is-is.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "JSON kerfi",207 "JSON Schema": "JSON kerfi",
208 "Type in the desired JSON schema": "Sláðu inn æskilegt JSON skema",208 "Type in the desired JSON schema": "Sláðu inn æskilegt JSON skema",
209 "Grammar String": "Málfræðistrengur",209 "Grammar String": "Málfræðistrengur",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF eða ENBF, fer eftir bakendanum sem er í notkun. Ef þú ert að nota þetta ættir þú að vita hvaða.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF eða EBNF, fer eftir bakendanum sem er í notkun. Ef þú ert að nota þetta ættir þú að vita hvaða.",
211 "Top P & Min P": "Efstu P & Min P",211 "Top P & Min P": "Efstu P & Min P",
212 "Load default order": "Hlaða sjálfgefna röð",212 "Load default order": "Hlaða sjálfgefna röð",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp eingöngu. Ákveður röð sýnataka. Ef Mirostat hamur er ekki 0, er röð sýnatöku hunsuð.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp eingöngu. Ákveður röð sýnataka. Ef Mirostat hamur er ekki 0, er röð sýnatöku hunsuð.",
public/locales/it-it.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "Schema JSON",207 "JSON Schema": "Schema JSON",
208 "Type in the desired JSON schema": "Digita lo schema JSON desiderato",208 "Type in the desired JSON schema": "Digita lo schema JSON desiderato",
209 "Grammar String": "Stringa grammaticale",209 "Grammar String": "Stringa grammaticale",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF o ENBF, dipende dal backend in uso. Se stai usando questo dovresti sapere quale.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF o EBNF, dipende dal backend in uso. Se stai usando questo dovresti sapere quale.",
211 "Top P & Min P": "P massimo e P minimo",211 "Top P & Min P": "P massimo e P minimo",
212 "Load default order": "Carica ordine predefinito",212 "Load default order": "Carica ordine predefinito",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "Solo lama.cpp. Determina l'ordine dei campionatori. Se la modalità Mirostat non è 0, l'ordine del campionatore viene ignorato.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "Solo lama.cpp. Determina l'ordine dei campionatori. Se la modalità Mirostat non è 0, l'ordine del campionatore viene ignorato.",
public/locales/ja-jp.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "JSONスキーマ",207 "JSON Schema": "JSONスキーマ",
208 "Type in the desired JSON schema": "希望するJSONスキーマを入力します",208 "Type in the desired JSON schema": "希望するJSONスキーマを入力します",
209 "Grammar String": "文法文字列",209 "Grammar String": "文法文字列",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF または ENBF は、使用するバックエンドによって異なります。これを使用する場合は、どちらであるかを知っておく必要があります。",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF または EBNF は、使用するバックエンドによって異なります。これを使用する場合は、どちらであるかを知っておく必要があります。",
211 "Top P & Min P": "トップPと最小P",211 "Top P & Min P": "トップPと最小P",
212 "Load default order": "デフォルトの順序を読み込む",212 "Load default order": "デフォルトの順序を読み込む",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp のみ。サンプラーの順序を決定します。Mirostat モードが 0 でない場合、サンプラーの順序は無視されます。",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp のみ。サンプラーの順序を決定します。Mirostat モードが 0 でない場合、サンプラーの順序は無視されます。",
public/locales/ko-kr.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "JSON 스키마",207 "JSON Schema": "JSON 스키마",
208 "Type in the desired JSON schema": "원하는 JSON 스키마를 입력하세요.",208 "Type in the desired JSON schema": "원하는 JSON 스키마를 입력하세요.",
209 "Grammar String": "문법 문자열",209 "Grammar String": "문법 문자열",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF 또는 ENBF는 사용 중인 백엔드에 따라 다릅니다. 이것을 사용한다면 어느 것이 무엇인지 알아야합니다.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 또는 EBNF는 사용 중인 백엔드에 따라 다릅니다. 이것을 사용한다면 어느 것이 무엇인지 알아야합니다.",
211 "Top P & Min P": "상위 P 및 최소 P",211 "Top P & Min P": "상위 P 및 최소 P",
212 "Load default order": "기본 순서로 로드",212 "Load default order": "기본 순서로 로드",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp만 가능합니다. 샘플러의 순서를 결정합니다. Mirostat 모드가 0이 아닌 경우 샘플러 순서는 무시됩니다.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp만 가능합니다. 샘플러의 순서를 결정합니다. Mirostat 모드가 0이 아닌 경우 샘플러 순서는 무시됩니다.",
public/locales/nl-nl.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "JSON-schema",207 "JSON Schema": "JSON-schema",
208 "Type in the desired JSON schema": "Typ het gewenste JSON-schema",208 "Type in the desired JSON schema": "Typ het gewenste JSON-schema",
209 "Grammar String": "Grammaticareeks",209 "Grammar String": "Grammaticareeks",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF of ENBF, hangt af van de gebruikte backend. Als u dit gebruikt, moet u weten welke.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF of EBNF, hangt af van de gebruikte backend. Als u dit gebruikt, moet u weten welke.",
211 "Top P & Min P": "Top P & Min P",211 "Top P & Min P": "Top P & Min P",
212 "Load default order": "Standaardvolgorde laden",212 "Load default order": "Standaardvolgorde laden",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "alleen lama.cpp. Bepaalt de volgorde van de samplers. Als de Mirostat-modus niet 0 is, wordt de samplervolgorde genegeerd.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "alleen lama.cpp. Bepaalt de volgorde van de samplers. Als de Mirostat-modus niet 0 is, wordt de samplervolgorde genegeerd.",
public/locales/pt-pt.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "Esquema JSON",207 "JSON Schema": "Esquema JSON",
208 "Type in the desired JSON schema": "Digite o esquema JSON desejado",208 "Type in the desired JSON schema": "Digite o esquema JSON desejado",
209 "Grammar String": "Cadeia de Gramática",209 "Grammar String": "Cadeia de Gramática",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF ou ENBF, depende do backend em uso. Se você estiver usando isso, você deve saber qual.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF ou EBNF, depende do backend em uso. Se você estiver usando isso, você deve saber qual.",
211 "Top P & Min P": "P superior e P mínimo",211 "Top P & Min P": "P superior e P mínimo",
212 "Load default order": "Carregar ordem padrão",212 "Load default order": "Carregar ordem padrão",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "apenas lhama.cpp. Determina a ordem dos amostradores. Se o modo Mirostat não for 0, a ordem do amostrador será ignorada.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "apenas lhama.cpp. Determina a ordem dos amostradores. Se o modo Mirostat não for 0, a ordem do amostrador será ignorada.",
public/locales/ru-ru.json+1 -1
@@ -978,7 +978,7 @@
978 "char_import_6": "Прямая ссылка на PNG-файл (чтобы узнать список разрешённых хостов, загляните в",978 "char_import_6": "Прямая ссылка на PNG-файл (чтобы узнать список разрешённых хостов, загляните в",
979 "char_import_7": ")",979 "char_import_7": ")",
980 "Grammar String": "Грамматика",980 "Grammar String": "Грамматика",
981 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF или ENBF, зависит от бэкенда. Если вы это используете, то, скорее всего, сами знаете, какой именно.",981 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF или EBNF, зависит от бэкенда. Если вы это используете, то, скорее всего, сами знаете, какой именно.",
982 "Account": "Аккаунт",982 "Account": "Аккаунт",
983 "Hi,": "Привет,",983 "Hi,": "Привет,",
984 "To enable multi-account features, restart the SillyTavern server with": "Чтобы активировать систему аккаунтов, перезапустите SillyTavern, выставив",984 "To enable multi-account features, restart the SillyTavern server with": "Чтобы активировать систему аккаунтов, перезапустите SillyTavern, выставив",
public/locales/uk-ua.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "Схема JSON",207 "JSON Schema": "Схема JSON",
208 "Type in the desired JSON schema": "Введіть потрібну схему JSON",208 "Type in the desired JSON schema": "Введіть потрібну схему JSON",
209 "Grammar String": "Граматичний рядок",209 "Grammar String": "Граматичний рядок",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF або ENBF, залежить від серверної частини, яка використовується. Якщо ви використовуєте це, ви повинні знати, який.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF або EBNF, залежить від серверної частини, яка використовується. Якщо ви використовуєте це, ви повинні знати, який.",
211 "Top P & Min P": "Верхній P & Min P",211 "Top P & Min P": "Верхній P & Min P",
212 "Load default order": "Завантажити типовий порядок",212 "Load default order": "Завантажити типовий порядок",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "лише llama.cpp. Визначає порядок пробовідбірників. Якщо режим Mirostat не 0, порядок вибірки ігнорується.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "лише llama.cpp. Визначає порядок пробовідбірників. Якщо режим Mirostat не 0, порядок вибірки ігнорується.",
public/locales/vi-vn.json+1 -1
@@ -207,7 +207,7 @@
207 "JSON Schema": "Lược đồ JSON",207 "JSON Schema": "Lược đồ JSON",
208 "Type in the desired JSON schema": "Nhập lược đồ JSON mong muốn",208 "Type in the desired JSON schema": "Nhập lược đồ JSON mong muốn",
209 "Grammar String": "Chuỗi ngữ pháp",209 "Grammar String": "Chuỗi ngữ pháp",
210 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF hoặc ENBF, tùy thuộc vào backend đang sử dụng. Nếu bạn đang sử dụng cái này, bạn nên biết cái nào.",210 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF hoặc EBNF, tùy thuộc vào backend đang sử dụng. Nếu bạn đang sử dụng cái này, bạn nên biết cái nào.",
211 "Top P & Min P": "P & P tối thiểu hàng đầu",211 "Top P & Min P": "P & P tối thiểu hàng đầu",
212 "Load default order": "Tải thứ tự mặc định",212 "Load default order": "Tải thứ tự mặc định",
213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "chỉ llama.cpp. Xác định thứ tự lấy mẫu. Nếu chế độ Mirostat khác 0, thứ tự lấy mẫu sẽ bị bỏ qua.",213 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "chỉ llama.cpp. Xác định thứ tự lấy mẫu. Nếu chế độ Mirostat khác 0, thứ tự lấy mẫu sẽ bị bỏ qua.",
public/locales/zh-cn.json+4 -2
@@ -208,7 +208,7 @@
208 "JSON Schema": "JSON 结构",208 "JSON Schema": "JSON 结构",
209 "Type in the desired JSON schema": "输入所需的 JSON 结构",209 "Type in the desired JSON schema": "输入所需的 JSON 结构",
210 "Grammar String": "语法字符串",210 "Grammar String": "语法字符串",
211 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF 或 ENBF,取决于使用的后端。如果您使用这个,您应该知道该用哪一个。",211 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 或 EBNF,取决于使用的后端。如果您使用这个,您应该知道该用哪一个。",
212 "Top P & Min P": "Top P 和 Min P",212 "Top P & Min P": "Top P 和 Min P",
213 "Load default order": "加载默认顺序",213 "Load default order": "加载默认顺序",
214 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "仅限 llama.cpp。确定采样器的顺序。如果 Mirostat 模式不为 0,则忽略采样器顺序。",214 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "仅限 llama.cpp。确定采样器的顺序。如果 Mirostat 模式不为 0,则忽略采样器顺序。",
@@ -443,7 +443,9 @@
443 "Example Separator": "示例分隔符",443 "Example Separator": "示例分隔符",
444 "Chat Start": "聊天开始",444 "Chat Start": "聊天开始",
445 "Add Chat Start and Example Separator to a list of stopping strings.": "将聊天开始和示例分隔符添加到停止字符串列表中。",445 "Add Chat Start and Example Separator to a list of stopping strings.": "将聊天开始和示例分隔符添加到停止字符串列表中。",
446 "Use as Stop Strings": "用作停止字符串",446 "Separators as Stop Strings": "分隔符作为终止字符串",
447 "Add Character and User names to a list of stopping strings.": "将角色和用户名添加到停止字符串列表中。",
448 "Names as Stop Strings": "名称作为终止字符串",
447 "context_allow_post_history_instructions": "如果在角色卡中定义并且启用了“首选角色卡说明”,则在提示末尾包含后历史说明。\n不建议在文本补全模型中使用此功能,否则会导致输出错误。",449 "context_allow_post_history_instructions": "如果在角色卡中定义并且启用了“首选角色卡说明”,则在提示末尾包含后历史说明。\n不建议在文本补全模型中使用此功能,否则会导致输出错误。",
448 "Allow Post-History Instructions": "允许后历史说明",450 "Allow Post-History Instructions": "允许后历史说明",
449 "Context Order": "上下文顺序",451 "Context Order": "上下文顺序",
public/locales/zh-tw.json+1 -1
@@ -208,7 +208,7 @@
208 "JSON Schema": "JSON 結構",208 "JSON Schema": "JSON 結構",
209 "Type in the desired JSON schema": "輸入所需的 JSON 結構",209 "Type in the desired JSON schema": "輸入所需的 JSON 結構",
210 "Grammar String": "語法字串",210 "Grammar String": "語法字串",
211 "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF 或 ENBF,取決於所使用的後端。如果您使用此功能,應該知道是哪一種",211 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 或 EBNF,取決於所使用的後端。如果您使用此功能,應該知道是哪一種",
212 "Top P & Min P": "Top P 和 Min P",212 "Top P & Min P": "Top P 和 Min P",
213 "Load default order": "載入預設順序",213 "Load default order": "載入預設順序",
214 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "僅適用於 llama.cpp。決定取樣器的順序。如果 Mirostat 模式不為 0,則忽略取樣器順序。",214 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "僅適用於 llama.cpp。決定取樣器的順序。如果 Mirostat 模式不為 0,則忽略取樣器順序。",
public/script.js+60 -146
@@ -227,7 +227,7 @@ import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay
227import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels } from './scripts/textgen-models.js';227import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels } from './scripts/textgen-models.js';
228import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId } from './scripts/chats.js';228import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId } from './scripts/chats.js';
229import { initPresetManager } from './scripts/preset-manager.js';229import { initPresetManager } from './scripts/preset-manager.js';
230import { MacrosParser, evaluateMacros } from './scripts/macros.js';230import { MacrosParser, evaluateMacros, getLastMessageId } from './scripts/macros.js';
231import { currentUser, setUserControls } from './scripts/user.js';231import { currentUser, setUserControls } from './scripts/user.js';
232import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js';232import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js';
233import { renderTemplate, renderTemplateAsync } from './scripts/templates.js';233import { renderTemplate, renderTemplateAsync } from './scripts/templates.js';
@@ -439,6 +439,7 @@ export const event_types = {
439 GROUP_CHAT_CREATED: 'group_chat_created',439 GROUP_CHAT_CREATED: 'group_chat_created',
440 GENERATE_BEFORE_COMBINE_PROMPTS: 'generate_before_combine_prompts',440 GENERATE_BEFORE_COMBINE_PROMPTS: 'generate_before_combine_prompts',
441 GENERATE_AFTER_COMBINE_PROMPTS: 'generate_after_combine_prompts',441 GENERATE_AFTER_COMBINE_PROMPTS: 'generate_after_combine_prompts',
442 GENERATE_AFTER_DATA: 'generate_after_data',
442 GROUP_MEMBER_DRAFTED: 'group_member_drafted',443 GROUP_MEMBER_DRAFTED: 'group_member_drafted',
443 WORLD_INFO_ACTIVATED: 'world_info_activated',444 WORLD_INFO_ACTIVATED: 'world_info_activated',
444 TEXT_COMPLETION_SETTINGS_READY: 'text_completion_settings_ready',445 TEXT_COMPLETION_SETTINGS_READY: 'text_completion_settings_ready',
@@ -1720,16 +1721,24 @@ export async function replaceCurrentChat() {
1720}1721}
17211722
1722export function showMoreMessages() {1723export function showMoreMessages() {
1723 let messageId = Number($('#chat').children('.mes').first().attr('mesid'));1724 const firstDisplayedMesId = $('#chat').children('.mes').first().attr('mesid');
1725 let messageId = Number(firstDisplayedMesId);
1724 let count = power_user.chat_truncation || Number.MAX_SAFE_INTEGER;1726 let count = power_user.chat_truncation || Number.MAX_SAFE_INTEGER;
17251727
1728 // If there are no messages displayed, or the message somehow has no mesid, we default to one higher than last message id,
1729 // so the first "new" message being shown will be the last available message
1730 if (isNaN(messageId)) {
1731 messageId = getLastMessageId() + 1;
1732 }
1733
1726 console.debug('Inserting messages before', messageId, 'count', count, 'chat length', chat.length);1734 console.debug('Inserting messages before', messageId, 'count', count, 'chat length', chat.length);
1727 const prevHeight = $('#chat').prop('scrollHeight');1735 const prevHeight = $('#chat').prop('scrollHeight');
17281736
1729 while (messageId > 0 && count > 0) {1737 while (messageId > 0 && count > 0) {
1738 let newMessageId = messageId - 1;
1739 addOneMessage(chat[newMessageId], { insertBefore: messageId >= chat.length ? null : messageId, scroll: false, forceId: newMessageId });
1730 count--;1740 count--;
1731 messageId--;1741 messageId--;
1732 addOneMessage(chat[messageId], { insertBefore: messageId + 1, scroll: false, forceId: messageId });
1733 }1742 }
17341743
1735 if (messageId == 0) {1744 if (messageId == 0) {
@@ -2470,26 +2479,30 @@ export function substituteParams(content, _name1, _name2, _original, _group, _re
2470 * @returns {string[]} Array of stopping strings2479 * @returns {string[]} Array of stopping strings
2471 */2480 */
2472export function getStoppingStrings(isImpersonate, isContinue) {2481export function getStoppingStrings(isImpersonate, isContinue) {
2473 const charString = `\n${name2}:`;2482 const result = [];
2474 const userString = `\n${name1}:`;
2475 const result = isImpersonate ? [charString] : [userString];
24762483
2477 result.push(userString);2484 if (power_user.context.names_as_stop_strings) {
2485 const charString = `\n${name2}:`;
2486 const userString = `\n${name1}:`;
2487 result.push(isImpersonate ? charString : userString);
24782488
2479 if (isContinue && Array.isArray(chat) && chat[chat.length - 1]?.is_user) {2489 result.push(userString);
2480 result.push(charString);
2481 }
24822490
2483 // Add other group members as the stopping strings2491 if (isContinue && Array.isArray(chat) && chat[chat.length - 1]?.is_user) {
2484 if (selected_group) {2492 result.push(charString);
2485 const group = groups.find(x => x.id === selected_group);2493 }
2494
2495 // Add other group members as the stopping strings
2496 if (selected_group) {
2497 const group = groups.find(x => x.id === selected_group);
24862498
2487 if (group && Array.isArray(group.members)) {2499 if (group && Array.isArray(group.members)) {
2488 const names = group.members2500 const names = group.members
2489 .map(x => characters.find(y => y.avatar == x))2501 .map(x => characters.find(y => y.avatar == x))
2490 .filter(x => x && x.name && x.name !== name2)2502 .filter(x => x && x.name && x.name !== name2)
2491 .map(x => `\n${x.name}:`);2503 .map(x => `\n${x.name}:`);
2492 result.push(...names);2504 result.push(...names);
2505 }
2493 }2506 }
2494 }2507 }
24952508
@@ -4211,6 +4224,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4211 }4224 }
4212 }4225 }
42134226
4227 await eventSource.emit(event_types.GENERATE_AFTER_DATA, generate_data);
4228
4214 if (dryRun) {4229 if (dryRun) {
4215 generatedPromptCache = '';4230 generatedPromptCache = '';
4216 return Promise.resolve();4231 return Promise.resolve();
@@ -5074,7 +5089,7 @@ function setInContextMessages(lastmsg, type) {
5074 * @param {object} data Generation data5089 * @param {object} data Generation data
5075 * @returns {Promise<object>} Response data from the API5090 * @returns {Promise<object>} Response data from the API
5076 */5091 */
5077async function sendGenerationRequest(type, data) {5092export async function sendGenerationRequest(type, data) {
5078 if (main_api === 'openai') {5093 if (main_api === 'openai') {
5079 return await sendOpenAIRequest(type, data.prompt, abortController.signal);5094 return await sendOpenAIRequest(type, data.prompt, abortController.signal);
5080 }5095 }
@@ -5106,7 +5121,7 @@ async function sendGenerationRequest(type, data) {
5106 * @param {object} data Generation data5121 * @param {object} data Generation data
5107 * @returns {Promise<any>} Streaming generator5122 * @returns {Promise<any>} Streaming generator
5108 */5123 */
5109async function sendStreamingRequest(type, data) {5124export async function sendStreamingRequest(type, data) {
5110 if (abortController?.signal?.aborted) {5125 if (abortController?.signal?.aborted) {
5111 throw new Error('Generation was aborted.');5126 throw new Error('Generation was aborted.');
5112 }5127 }
@@ -7917,6 +7932,8 @@ window['SillyTavern'].getContext = function () {
7917 eventTypes: event_types,7932 eventTypes: event_types,
7918 addOneMessage: addOneMessage,7933 addOneMessage: addOneMessage,
7919 generate: Generate,7934 generate: Generate,
7935 sendStreamingRequest: sendStreamingRequest,
7936 sendGenerationRequest: sendGenerationRequest,
7920 stopGeneration: stopGeneration,7937 stopGeneration: stopGeneration,
7921 getTokenCount: getTokenCount,7938 getTokenCount: getTokenCount,
7922 extensionPrompts: extension_prompts,7939 extensionPrompts: extension_prompts,
@@ -8310,6 +8327,7 @@ const swipe_right = () => {
8310};8327};
83118328
8312const CONNECT_API_MAP = {8329const CONNECT_API_MAP = {
8330 // Default APIs not contined inside text gen / chat gen
8313 'kobold': {8331 'kobold': {
8314 selected: 'kobold',8332 selected: 'kobold',
8315 button: '#api_button',8333 button: '#api_button',
@@ -8321,152 +8339,48 @@ const CONNECT_API_MAP = {
8321 selected: 'novel',8339 selected: 'novel',
8322 button: '#api_button_novel',8340 button: '#api_button_novel',
8323 },8341 },
8324 'ooba': {8342 // KoboldCpp alias
8325 selected: 'textgenerationwebui',
8326 button: '#api_button_textgenerationwebui',
8327 type: textgen_types.OOBA,
8328 },
8329 'tabby': {
8330 selected: 'textgenerationwebui',
8331 button: '#api_button_textgenerationwebui',
8332 type: textgen_types.TABBY,
8333 },
8334 'llamacpp': {
8335 selected: 'textgenerationwebui',
8336 button: '#api_button_textgenerationwebui',
8337 type: textgen_types.LLAMACPP,
8338 },
8339 'ollama': {
8340 selected: 'textgenerationwebui',
8341 button: '#api_button_textgenerationwebui',
8342 type: textgen_types.OLLAMA,
8343 },
8344 'mancer': {
8345 selected: 'textgenerationwebui',
8346 button: '#api_button_textgenerationwebui',
8347 type: textgen_types.MANCER,
8348 },
8349 'vllm': {
8350 selected: 'textgenerationwebui',
8351 button: '#api_button_textgenerationwebui',
8352 type: textgen_types.VLLM,
8353 },
8354 'aphrodite': {
8355 selected: 'textgenerationwebui',
8356 button: '#api_button_textgenerationwebui',
8357 type: textgen_types.APHRODITE,
8358 },
8359 'koboldcpp': {
8360 selected: 'textgenerationwebui',
8361 button: '#api_button_textgenerationwebui',
8362 type: textgen_types.KOBOLDCPP,
8363 },
8364 'kcpp': {8343 'kcpp': {
8365 selected: 'textgenerationwebui',8344 selected: 'textgenerationwebui',
8366 button: '#api_button_textgenerationwebui',8345 button: '#api_button_textgenerationwebui',
8367 type: textgen_types.KOBOLDCPP,8346 type: textgen_types.KOBOLDCPP,
8368 },8347 },
8369 'togetherai': {8348 // OpenAI alias
8370 selected: 'textgenerationwebui',
8371 button: '#api_button_textgenerationwebui',
8372 type: textgen_types.TOGETHERAI,
8373 },
8374 'openai': {
8375 selected: 'openai',
8376 button: '#api_button_openai',
8377 source: chat_completion_sources.OPENAI,
8378 },
8379 'oai': {8349 'oai': {
8380 selected: 'openai',8350 selected: 'openai',
8381 button: '#api_button_openai',8351 button: '#api_button_openai',
8382 source: chat_completion_sources.OPENAI,8352 source: chat_completion_sources.OPENAI,
8383 },8353 },
8384 'claude': {8354 // OpenRouter special naming, to differentiate between chat comp and text comp
8385 selected: 'openai',
8386 button: '#api_button_openai',
8387 source: chat_completion_sources.CLAUDE,
8388 },
8389 'windowai': {
8390 selected: 'openai',
8391 button: '#api_button_openai',
8392 source: chat_completion_sources.WINDOWAI,
8393 },
8394 'openrouter': {8355 'openrouter': {
8395 selected: 'openai',8356 selected: 'openai',
8396 button: '#api_button_openai',8357 button: '#api_button_openai',
8397 source: chat_completion_sources.OPENROUTER,8358 source: chat_completion_sources.OPENROUTER,
8398 },8359 },
8399 'scale': {
8400 selected: 'openai',
8401 button: '#api_button_openai',
8402 source: chat_completion_sources.SCALE,
8403 },
8404 'ai21': {
8405 selected: 'openai',
8406 button: '#api_button_openai',
8407 source: chat_completion_sources.AI21,
8408 },
8409 'makersuite': {
8410 selected: 'openai',
8411 button: '#api_button_openai',
8412 source: chat_completion_sources.MAKERSUITE,
8413 },
8414 'mistralai': {
8415 selected: 'openai',
8416 button: '#api_button_openai',
8417 source: chat_completion_sources.MISTRALAI,
8418 },
8419 'custom': {
8420 selected: 'openai',
8421 button: '#api_button_openai',
8422 source: chat_completion_sources.CUSTOM,
8423 },
8424 'cohere': {
8425 selected: 'openai',
8426 button: '#api_button_openai',
8427 source: chat_completion_sources.COHERE,
8428 },
8429 'perplexity': {
8430 selected: 'openai',
8431 button: '#api_button_openai',
8432 source: chat_completion_sources.PERPLEXITY,
8433 },
8434 'groq': {
8435 selected: 'openai',
8436 button: '#api_button_openai',
8437 source: chat_completion_sources.GROQ,
8438 },
8439 '01ai': {
8440 selected: 'openai',
8441 button: '#api_button_openai',
8442 source: chat_completion_sources.ZEROONEAI,
8443 },
8444 'infermaticai': {
8445 selected: 'textgenerationwebui',
8446 button: '#api_button_textgenerationwebui',
8447 type: textgen_types.INFERMATICAI,
8448 },
8449 'dreamgen': {
8450 selected: 'textgenerationwebui',
8451 button: '#api_button_textgenerationwebui',
8452 type: textgen_types.DREAMGEN,
8453 },
8454 'openrouter-text': {8360 'openrouter-text': {
8455 selected: 'textgenerationwebui',8361 selected: 'textgenerationwebui',
8456 button: '#api_button_textgenerationwebui',8362 button: '#api_button_textgenerationwebui',
8457 type: textgen_types.OPENROUTER,8363 type: textgen_types.OPENROUTER,
8458 },8364 },
8459 'featherless': {8365};
8460 selected: 'textgenerationwebui',8366
8461 button: '#api_button_textgenerationwebui',8367// Fill connections map from textgen_types and chat_completion_sources
8462 type: textgen_types.FEATHERLESS,8368for (const textGenType of Object.values(textgen_types)) {
8463 },8369 if (CONNECT_API_MAP[textGenType]) continue;
8464 'huggingface': {8370 CONNECT_API_MAP[textGenType] = {
8465 selected: 'textgenerationwebui',8371 selected: 'textgenerationwebui',
8466 button: '#api_button_textgenerationwebui',8372 button: '#api_button_textgenerationwebui',
8467 type: textgen_types.HUGGINGFACE,8373 type: textGenType,
8468 },8374 };
8469};8375}
8376for (const chatCompletionSource of Object.values(chat_completion_sources)) {
8377 if (CONNECT_API_MAP[chatCompletionSource]) continue;
8378 CONNECT_API_MAP[chatCompletionSource] = {
8379 selected: 'openai',
8380 button: '#api_button_openai',
8381 source: chatCompletionSource,
8382 };
8383}
84708384
8471async function selectContextCallback(_, name) {8385async function selectContextCallback(_, name) {
8472 if (!name) {8386 if (!name) {
@@ -8599,7 +8513,7 @@ export async function processDroppedFiles(files, data = new Map()) {
85998513
8600 for (const file of files) {8514 for (const file of files) {
8601 const extension = file.name.split('.').pop().toLowerCase();8515 const extension = file.name.split('.').pop().toLowerCase();
8602 if (allowedMimeTypes.includes(file.type) || allowedExtensions.includes(extension)) {8516 if (allowedMimeTypes.some(x => file.type.startsWith(x)) || allowedExtensions.includes(extension)) {
8603 const preservedName = data instanceof Map && data.get(file);8517 const preservedName = data instanceof Map && data.get(file);
8604 await importCharacter(file, preservedName);8518 await importCharacter(file, preservedName);
8605 } else {8519 } else {
public/scripts/popup.js+21 -6
@@ -101,6 +101,21 @@ const showPopupHelper = {
101 if (typeof result === 'string' || typeof result === 'boolean') throw new Error(`Invalid popup result. CONFIRM popups only support numbers, or null. Result: ${result}`);101 if (typeof result === 'string' || typeof result === 'boolean') throw new Error(`Invalid popup result. CONFIRM popups only support numbers, or null. Result: ${result}`);
102 return result;102 return result;
103 },103 },
104 /**
105 * Asynchronously displays a text popup with the given header and text, returning the clicked result button value.
106 *
107 * @param {string?} header - The header text for the popup.
108 * @param {string?} text - The main text for the popup.
109 * @param {PopupOptions} [popupOptions={}] - Options for the popup.
110 * @return {Promise<POPUP_RESULT>} A Promise that resolves with the result of the user's interaction.
111 */
112 text: async (header, text, popupOptions = {}) => {
113 const content = PopupUtils.BuildTextWithHeader(header, text);
114 const popup = new Popup(content, POPUP_TYPE.TEXT, null, popupOptions);
115 const result = await popup.show();
116 if (typeof result === 'string' || typeof result === 'boolean') throw new Error(`Invalid popup result. TEXT popups only support numbers, or null. Result: ${result}`);
117 return result;
118 },
104};119};
105120
106export class Popup {121export class Popup {
@@ -511,14 +526,14 @@ export class Popup {
511526
512 return this.#promise;527 return this.#promise;
513 }528 }
514 completeAffirmative() {529 async completeAffirmative() {
515 return this.complete(POPUP_RESULT.AFFIRMATIVE);530 return await this.complete(POPUP_RESULT.AFFIRMATIVE);
516 }531 }
517 completeNegative() {532 async completeNegative() {
518 return this.complete(POPUP_RESULT.NEGATIVE);533 return await this.complete(POPUP_RESULT.NEGATIVE);
519 }534 }
520 completeCancelled() {535 async completeCancelled() {
521 return this.complete(POPUP_RESULT.CANCELLED);536 return await this.complete(POPUP_RESULT.CANCELLED);
522 }537 }
523538
524 /**539 /**
public/scripts/power-user.js+2 -0
@@ -242,6 +242,7 @@ let power_user = {
242 example_separator: defaultExampleSeparator,242 example_separator: defaultExampleSeparator,
243 use_stop_strings: true,243 use_stop_strings: true,
244 allow_jailbreak: false,244 allow_jailbreak: false,
245 names_as_stop_strings: true,
245 },246 },
246247
247 personas: {},248 personas: {},
@@ -348,6 +349,7 @@ const contextControls = [
348 { id: 'context_chat_start', property: 'chat_start', isCheckbox: false, isGlobalSetting: false },349 { id: 'context_chat_start', property: 'chat_start', isCheckbox: false, isGlobalSetting: false },
349 { id: 'context_use_stop_strings', property: 'use_stop_strings', isCheckbox: true, isGlobalSetting: false, defaultValue: false },350 { id: 'context_use_stop_strings', property: 'use_stop_strings', isCheckbox: true, isGlobalSetting: false, defaultValue: false },
350 { id: 'context_allow_jailbreak', property: 'allow_jailbreak', isCheckbox: true, isGlobalSetting: false, defaultValue: false },351 { id: 'context_allow_jailbreak', property: 'allow_jailbreak', isCheckbox: true, isGlobalSetting: false, defaultValue: false },
352 { id: 'context_names_as_stop_strings', property: 'names_as_stop_strings', isCheckbox: true, isGlobalSetting: false, defaultValue: true },
351353
352 // Existing power user settings354 // Existing power user settings
353 { id: 'always-force-name2-checkbox', property: 'always_force_name2', isCheckbox: true, isGlobalSetting: true, defaultValue: true },355 { id: 'always-force-name2-checkbox', property: 'always_force_name2', isCheckbox: true, isGlobalSetting: true, defaultValue: true },
public/scripts/samplerSelect.js+2 -2
@@ -158,12 +158,12 @@ async function showSamplerSelectPopup() {
158 <div class="flex-container justifyCenter">158 <div class="flex-container justifyCenter">
159 <h3>Sampler Select</h3>159 <h3>Sampler Select</h3>
160 <div class="flex-container alignItemsBaseline">160 <div class="flex-container alignItemsBaseline">
161 <div id="resetSelectedSamplers" class="menu_button menu_button_icon tag_view_create" title="Reset custom sampler selection">161 <div id="resetSelectedSamplers" class="menu_button menu_button_icon" title="Reset custom sampler selection">
162 <i class="fa-solid fa-recycle"></i>162 <i class="fa-solid fa-recycle"></i>
163 </div>163 </div>
164 </div>164 </div>
165 <!--<div class="flex-container alignItemsBaseline">165 <!--<div class="flex-container alignItemsBaseline">
166 <div class="menu_button menu_button_icon tag_view_create" title="Create a new sampler">166 <div class="menu_button menu_button_icon" title="Create a new sampler">
167 <i class="fa-solid fa-plus"></i>167 <i class="fa-solid fa-plus"></i>
168 <span data-i18n="Create">Create</span>168 <span data-i18n="Create">Create</span>
169 </div>169 </div>
public/scripts/tags.js+50 -32
@@ -21,7 +21,7 @@ import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
21import { SlashCommand } from './slash-commands/SlashCommand.js';21import { SlashCommand } from './slash-commands/SlashCommand.js';
22import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';22import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
23import { isMobile } from './RossAscends-mods.js';23import { isMobile } from './RossAscends-mods.js';
24import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from './popup.js';24import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
25import { debounce_timeout } from './constants.js';25import { debounce_timeout } from './constants.js';
26import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js';26import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js';
27import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js';27import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js';
@@ -1367,27 +1367,8 @@ function makeTagListDraggable(tagContainer) {
1367 const id = $(tagElement).attr('id');1367 const id = $(tagElement).attr('id');
1368 const tag = tags.find(x => x.id === id);1368 const tag = tags.find(x => x.id === id);
13691369
1370 // Fix the defined colors, because if there is no color set, they seem to get automatically set to black
1371 // based on the color picker after drag&drop, even if there was no color chosen. We just set them back.
1372 const color = $(tagElement).find('.tagColorPickerHolder .tag-color').attr('color');
1373 const color2 = $(tagElement).find('.tagColorPicker2Holder .tag-color2').attr('color');
1374 if (color === '' || color === undefined) {
1375 tag.color = '';
1376 fixColor('background-color', tag.color);
1377 }
1378 if (color2 === '' || color2 === undefined) {
1379 tag.color2 = '';
1380 fixColor('color', tag.color2);
1381 }
1382
1383 // Update the sort order1370 // Update the sort order
1384 tag.sort_order = i;1371 tag.sort_order = i;
1385
1386 function fixColor(property, color) {
1387 $(tagElement).find('.tag_view_name').css(property, color);
1388 $(`.tag[id="${id}"]`).css(property, color);
1389 $(`.bogus_folder_select[tagid="${id}"] .avatar`).css(property, color);
1390 }
1391 });1372 });
13921373
1393 // If tags were dragged manually, we have to disable auto sorting1374 // If tags were dragged manually, we have to disable auto sorting
@@ -1455,18 +1436,28 @@ async function onTagRestoreFileSelect(e) {
1455 const data = await parseJsonFile(file);1436 const data = await parseJsonFile(file);
14561437
1457 if (!data) {1438 if (!data) {
1458 toastr.warning('Empty file data', 'Tag restore');1439 toastr.warning('Empty file data', 'Tag Restore');
1459 console.log('Tag restore: File data empty.');1440 console.log('Tag restore: File data empty.');
1460 return;1441 return;
1461 }1442 }
14621443
1463 if (!data.tags || !data.tag_map || !Array.isArray(data.tags) || typeof data.tag_map !== 'object') {1444 if (!data.tags || !data.tag_map || !Array.isArray(data.tags) || typeof data.tag_map !== 'object') {
1464 toastr.warning('Invalid file format', 'Tag restore');1445 toastr.warning('Invalid file format', 'Tag Restore');
1465 console.log('Tag restore: Invalid file format.');1446 console.log('Tag restore: Invalid file format.');
1466 return;1447 return;
1467 }1448 }
14681449
1450 // Prompt user if they want to overwrite existing tags
1451 let overwrite = false;
1452 if (tags.length > 0) {
1453 const result = await Popup.show.confirm('Tag Restore', 'You have existing tags. If the backup contains any of those tags, do you want the backup to overwrite their settings (Name, color, folder state, etc)?',
1454 { okButton: 'Overwrite', cancelButton: 'Keep Existing' });
1455 overwrite = result === POPUP_RESULT.AFFIRMATIVE;
1456 }
1457
1469 const warnings = [];1458 const warnings = [];
1459 /** @type {Map<string, string>} Map import tag ids with existing ids on overwrite */
1460 const idToActualTagIdMap = new Map();
14701461
1471 // Import tags1462 // Import tags
1472 for (const tag of data.tags) {1463 for (const tag of data.tags) {
@@ -1475,11 +1466,29 @@ async function onTagRestoreFileSelect(e) {
1475 continue;1466 continue;
1476 }1467 }
14771468
1478 if (tags.find(x => x.id === tag.id)) {1469 // Check against both existing id (direct match) and tag with the same name, which is not allowed.
1479 warnings.push(`Tag with id ${tag.id} already exists.`);1470 let existingTag = tags.find(x => x.id === tag.id);
1471 if (existingTag && !overwrite) {
1472 warnings.push(`Tag '${tag.name}' with id ${tag.id} already exists.`);
1473 continue;
1474 }
1475 existingTag = getTag(tag.name);
1476 if (existingTag && !overwrite) {
1477 warnings.push(`Tag with name '${tag.name}' already exists.`);
1478 // Remember the tag id, so we can still import the tag map entries for this
1479 idToActualTagIdMap.set(tag.id, existingTag.id);
1480 continue;1480 continue;
1481 }1481 }
14821482
1483 if (existingTag) {
1484 // On overwrite, we remove and re-add the tag
1485 removeFromArray(tags, existingTag);
1486 // And remember the ID if it was different, so we can update the tag map accordingly
1487 if (existingTag.id !== tag.id) {
1488 idToActualTagIdMap.set(existingTag.id, tag.id);
1489 }
1490 }
1491
1483 tags.push(tag);1492 tags.push(tag);
1484 }1493 }
14851494
@@ -1497,30 +1506,39 @@ async function onTagRestoreFileSelect(e) {
1497 const groupExists = groups.some(x => String(x.id) === String(key));1506 const groupExists = groups.some(x => String(x.id) === String(key));
14981507
1499 if (!characterExists && !groupExists) {1508 if (!characterExists && !groupExists) {
1500 warnings.push(`Tag map key ${key} does not exist.`);1509 warnings.push(`Tag map key ${key} does not exist as character or group.`);
1501 continue;1510 continue;
1502 }1511 }
15031512
1504 // Get existing tag ids for this key or empty array.1513 // Get existing tag ids for this key or empty array.
1505 const existingTagIds = tag_map[key] || [];1514 const existingTagIds = tag_map[key] || [];
1506 // Merge existing and new tag ids. Remove duplicates.1515
1507 tag_map[key] = existingTagIds.concat(tagIds).filter(onlyUnique);1516 // Merge existing and new tag ids. Replace the ones mapped to a new id. Remove duplicates.
1517 const combinedTags = existingTagIds.concat(tagIds)
1518 .map(tagId => (idToActualTagIdMap.has(tagId)) ? idToActualTagIdMap.get(tagId) : tagId)
1519 .filter(onlyUnique);
1520
1508 // Verify that all tags exist. Remove tags that don't exist.1521 // Verify that all tags exist. Remove tags that don't exist.
1509 tag_map[key] = tag_map[key].filter(x => tags.some(y => String(y.id) === String(x)));1522 tag_map[key] = combinedTags.filter(tagId => tags.some(y => String(y.id) === String(tagId)));
1510 }1523 }
15111524
1512 if (warnings.length) {1525 if (warnings.length) {
1513 toastr.success('Tags restored with warnings. Check console for details.');1526 toastr.warning('Tags restored with warnings. Check console or click on this message for details.', 'Tag Restore', {
1527 timeOut: toastr.options.timeOut * 2, // Display double the time
1528 onclick: () => Popup.show.text('Tag Restore Warnings', `<samp class="justifyLeft">${DOMPurify.sanitize(warnings.join('\n'))}<samp>`, { allowVerticalScrolling: true }),
1529 });
1514 console.warn(`TAG RESTORE REPORT\n====================\n${warnings.join('\n')}`);1530 console.warn(`TAG RESTORE REPORT\n====================\n${warnings.join('\n')}`);
1515 } else {1531 } else {
1516 toastr.success('Tags restored successfully.');1532 toastr.success('Tags restored successfully.', 'Tag Restore');
1517 }1533 }
15181534
1519 $('#tag_view_restore_input').val('');1535 $('#tag_view_restore_input').val('');
1520 printCharactersDebounced();1536 printCharactersDebounced();
1521 saveSettingsDebounced();1537 saveSettingsDebounced();
15221538
1523 await onViewTagsListClick();1539 // Reprint the tag management popup, without having it to be opened again
1540 const tagContainer = $('#tag_view_list .tag_view_list_tags');
1541 printViewTagList(tagContainer);
1524}1542}
15251543
1526function onBackupRestoreClick() {1544function onBackupRestoreClick() {
@@ -1577,7 +1595,7 @@ function appendViewTagToList(list, tag, everything) {
15771595
1578 const primaryColorPicker = $('<toolcool-color-picker></toolcool-color-picker>')1596 const primaryColorPicker = $('<toolcool-color-picker></toolcool-color-picker>')
1579 .addClass('tag-color')1597 .addClass('tag-color')
1580 .attr({ id: colorPickerId, color: tag.color || 'rgba(0, 0, 0, 0.3)', 'data-default-color': 'rgba(0, 0, 0, 0.3)' });1598 .attr({ id: colorPickerId, color: tag.color || 'rgba(0, 0, 0, 0.5)', 'data-default-color': 'rgba(0, 0, 0, 0.5)' });
15811599
1582 const secondaryColorPicker = $('<toolcool-color-picker></toolcool-color-picker>')1600 const secondaryColorPicker = $('<toolcool-color-picker></toolcool-color-picker>')
1583 .addClass('tag-color2')1601 .addClass('tag-color2')
public/scripts/world-info.js+1 -1
@@ -3584,7 +3584,7 @@ export async function getSortedEntries() {
35843584
3585 // Parse decorators3585 // Parse decorators
3586 entries = entries.map((entry) => {3586 entries = entries.map((entry) => {
3587 const [decorators, content] = parseDecorators(entry.content);3587 const [decorators, content] = parseDecorators(entry.content || '');
3588 return { ...entry, decorators, content };3588 return { ...entry, decorators, content };
3589 });3589 });
35903590
public/style.css+7 -0
@@ -470,6 +470,13 @@ kbd {
470 line-height: 1;470 line-height: 1;
471}471}
472472
473samp {
474 display: block;
475 font-family: var(--monoFontFamily);
476 white-space: pre-wrap;
477 text-align: start;
478 justify-content: left;
479}
473480
474hr {481hr {
475 background-image: linear-gradient(90deg, var(--transparent), var(--SmartThemeBodyColor), var(--transparent));482 background-image: linear-gradient(90deg, var(--transparent), var(--SmartThemeBodyColor), var(--transparent));
src/constants.js+3 -0
@@ -312,6 +312,9 @@ const TOGETHERAI_KEYS = [
312 'top_p',312 'top_p',
313 'top_k',313 'top_k',
314 'repetition_penalty',314 'repetition_penalty',
315 'min_p',
316 'presence_penalty',
317 'frequency_penalty',
315 'stream',318 'stream',
316 'stop',319 'stop',
317];320];