Compare commits

...

36 Commits

Author SHA1 Message Date
Cohee 0b3c49da90 Allow bulk edit menu to wrap 2024-05-18 17:59:59 +03:00
Cohee c3d6e10795 Fix error on creating new tags 2024-05-18 17:55:22 +03:00
Cohee 1eae9bd18b Draw updated tags immediately 2024-05-18 17:51:42 +03:00
Cohee 99e24f5588 Fix group tags opacity 2024-05-18 17:51:10 +03:00
Cohee 38e2bf955c Merge branch 'staging' into tag-slash-commands 2024-05-18 17:27:04 +03:00
Cohee 0653dad5c5 Show tags when auto-loading a character 2024-05-18 17:05:46 +03:00
Cohee 51af830db8 Only auto-select preset on full name match 2024-05-18 16:46:41 +03:00
Cohee 2bde9d2b15 Merge branch 'staging' into tag-slash-commands 2024-05-18 16:42:25 +03:00
Cohee d9f9da99e6 Silent /abort 2024-05-18 15:41:02 +03:00
Cohee 64b0123acf
Merge pull request #2263 from PasserDreamer/staging
Fix some typo and add zh-tw locale.
2024-05-18 14:48:47 +03:00
Cohee 35d853b851 Normalize "Default" and "Match Whole Words" data-i18n 2024-05-18 14:43:06 +03:00
Cohee 1966baad84 Fix invalid JSON format 2024-05-18 14:39:04 +03:00
Cohee a398566b33 [BUG]In the lorebooks management panel, when in the Custom sorting mode, entries may be incorrectly placed above the table header. #2262 2024-05-18 13:27:22 +03:00
PasserDreamer 9f2c473040
Add files via upload
Add zh-TW locale.
2024-05-18 17:23:54 +08:00
PasserDreamer a73db4984a
Merge pull request #3 from PasserDreamer/patch-3
Update mediawiki-scrape.html
2024-05-18 17:21:45 +08:00
PasserDreamer 3498eb92bb
Merge pull request #2 from PasserDreamer/patch-1
Update fandom-scrape.html
2024-05-18 17:17:25 +08:00
PasserDreamer 455db18d71
Merge pull request #1 from PasserDreamer/patch-2
Update index.html
2024-05-18 17:16:37 +08:00
PasserDreamer 2aeffe4095
Update mediawiki-scrape.html
fix typo
2024-05-18 15:58:32 +08:00
PasserDreamer c4fe9749d5
Update index.html
Correct typos and standardize the capitalization of repeated terms.
2024-05-18 15:52:42 +08:00
PasserDreamer a0512585b1
Update fandom-scrape.html
fix missing qoutes.
2024-05-18 15:34:05 +08:00
Cohee c52bdb9a4a Use new command names in examples 2024-05-17 20:59:00 +03:00
Cohee bbd9c89357 Add aliases for group member commands 2024-05-17 20:57:03 +03:00
Cohee fb2190ace1 #2254 Don't suppress abort in subcommands 2024-05-17 18:21:13 +03:00
Cohee deb09bf5bf Fix console errors on not found command autocomplete 2024-05-17 17:47:40 +03:00
Cohee d951beb626 #2260 Handle window resize in script editor 2024-05-17 17:47:18 +03:00
Cohee 748dd5f2e6 Remove duplicate command registration 2024-05-17 15:04:53 +03:00
Cohee 75de4c8fcb Resolve boolean fields to constant values when searching WI entries with command 2024-05-17 14:32:57 +03:00
Cohee 432be09583
Merge pull request #2259 from Succubyss/staging
[Claude] Implements Assistant Impersonation Prefill
2024-05-17 11:15:37 +03:00
Succubyss c822b9e2da Implements Assistant Impersonation Prefill 2024-05-16 21:59:58 -05:00
Cohee c661fea07d #2227 Implement content scaffolding 2024-05-17 02:43:14 +03:00
Cohee 782f85e05d
Merge pull request #2233 from Bronya-Rand/staging
feat: add default tip to welcome screen
2024-05-17 02:07:01 +03:00
Bronya-Rand 9475147435 chore: adjustments to the bundle notice and update spanish locale 2024-05-16 17:45:42 -05:00
Cohee ea45d372f3 Reformat es-es for cleaner diff 2024-05-14 19:57:31 +03:00
Bronya-Rand 6ec51ff086 chore: slight english updates and spanish translation cuz I know it 2024-05-14 10:02:04 +01:00
Azariel Del Carmen 9eae4d9739
Merge branch 'SillyTavern:staging' into staging 2024-05-14 10:47:08 +01:00
Bronya-Rand 84aa746241 feat: add default asset tip to welcome screen 2024-05-14 09:46:37 +01:00
36 changed files with 1419 additions and 118 deletions

1
.gitignore vendored
View File

@ -47,3 +47,4 @@ access.log
public/css/user.css
/plugins/
/data
/default/scaffold

View File

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

View File

@ -624,6 +624,7 @@
"show_external_models": false,
"proxy_password": "",
"assistant_prefill": "",
"assistant_impersonation": "",
"use_ai21_tokenizer": false
}
}

View File

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

View File

@ -103,7 +103,8 @@
}
#bulkTagsList,
#tagList .tag {
#tagList .tag,
#groupTagList .tag {
opacity: 0.6;
}

View File

@ -116,7 +116,7 @@
</h4>
<div class="flex-container flexNoGap">
<select id="settings_preset_novel" class="flex1 text_pole" data-preset-manager-for="novel">
<option value="gui" data-i18n="default">Default</option>
<option value="gui" data-i18n="Default">Default</option>
</select>
<div class="flex-container marginLeft5 ">
<input type="file" hidden data-preset-manager-file="novel" accept=".json, .settings">
@ -134,7 +134,7 @@
<h4 class="margin0"><span data-i18n="openaipresets">Chat Completion Presets</span></h4>
<div class="flex-container flexNoGap">
<select id="settings_preset_openai" class="flex1 text_pole" data-preset-manager-for="openai">
<option value="gui" data-i18n="default">Default</option>
<option value="gui" data-i18n="Default">Default</option>
</select>
<div class="flex-container marginLeft5 ">
<input id="openai_preset_import_file" type="file" accept=".json,.settings" hidden />
@ -246,7 +246,7 @@
</div>
</div>
<div class="range-block">
<div class="range-block-title" data-i18n="temperature">
<div class="range-block-title" data-i18n="Temperature">
Temperature
</div>
<div class="range-block-range-and-counter">
@ -1268,13 +1268,12 @@
</div>
</div>
<div data-newbie-hidden data-tg-type="ooba, mancer, koboldcpp, tabby, llamacpp, aphrodite" name="dynaTempBlock" class="wide100p">
<h4 class="wide100p textAlignCenter" data-i18n="DynaTemp">
<div class="flex-container alignitemscenter" style="justify-content: center;">
<h4 class="wide100p textAlignCenter">
<div class="flex-container alignitemscenter justifyCenter">
<div class="checkbox_label" for="dynatemp_textgenerationwebui">
<input type="checkbox" id="dynatemp_textgenerationwebui" />
<small data-i18n="dynatemp"></small>
</div>
<span style="text-align: center;" data-i18n="Dynamic Temperature">Dynamic Temperature</span>
<span class="textAlignCenter" data-i18n="Dynamic Temperature">Dynamic Temperature</span>
<div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Scale Temperature dynamically per token, based on the variation of probabilities" title="Scale Temperature dynamically per token, based on the variation of probabilities."></div>
</div>
</h4>
@ -1734,6 +1733,8 @@
<div class="wide100p">
<span id="claude_assistant_prefill_text" data-i18n="Assistant Prefill">Assistant Prefill</span>
<textarea id="claude_assistant_prefill" class="text_pole textarea_compact" name="assistant_prefill autoSetHeight" rows="3" maxlength="10000" data-i18n="[placeholder]Start Claude's answer with..." placeholder="Start Claude's answer with..."></textarea>
<span id="claude_assistant_impersonation_text" data-i18n="Assistant Impersonation Prefill">Assistant Impersonation Prefill</span>
<textarea id="claude_assistant_impersonation" class="text_pole textarea_compact" name="assistant_impersonation autoSetHeight" rows="3" maxlength="10000" data-i18n="[placeholder]Start Claude's answer with..." placeholder="Start Claude's answer with..."></textarea>
</div>
<label for="claude_use_sysprompt" class="checkbox_label widthFreeExpand">
<input id="claude_use_sysprompt" type="checkbox" />
@ -3443,8 +3444,8 @@
</label>
<label title="If the entry key consists of only one word, it would not be matched as part of other words" data-i18n="[title]If the entry key consists of only one word, it would not be matched as part of other words" class="checkbox_label flex1">
<input id="world_info_match_whole_words" type="checkbox" />
<small data-i18n="Match whole words" class="whitespacenowrap flex1">
Match whole words
<small data-i18n="Match Whole Words" class="whitespacenowrap flex1">
Match Whole Words
</small>
</label>
<label title="Only the entries with the most number of key matches will be selected for Inclusion Group filtering" data-i18n="[title]Only the entries with the most number of key matches will be selected for Inclusion Group filtering" class="checkbox_label flex1">
@ -3597,7 +3598,7 @@
<div class="flex-container">
<span data-i18n="Chat Style:">Chat Style:</span><br>
<select id="chat_display" class="widthNatural flex1 margin0">
<option value="0" data-i18n="Default">Flat</span>
<option value="0" data-i18n="Flat">Flat</span>
<option value="1" data-i18n="Bubbles">Bubbles</option>
<option value="2" data-i18n="Document">Document</option>
</select>
@ -4082,7 +4083,7 @@
<small class="fa-solid fa-circle-question note-link-small"></small>
</a>
</label>
<label class="checkbox_label" for="forbid_external_media" title="Disalow embedded media from other domains in chat messages." data-i18n="[title]Disalow embedded media from other domains in chat messages">
<label class="checkbox_label" for="forbid_external_media" title="Disallow embedded media from other domains in chat messages." data-i18n="[title]Disallow embedded media from other domains in chat messages">
<input id="forbid_external_media" type="checkbox" />
<small data-i18n="Forbid External Media">Forbid External Media</small>
</label>

View File

@ -3,7 +3,6 @@
"kobldpresets": "الإعدادات المسبقة لـ Kobold",
"guikoboldaisettings": "إعدادات واجهة KoboldAI",
"novelaipreserts": "الإعدادات المسبقة لـ NovelAI",
"default": "افتراضي",
"openaipresets": "الإعدادات المسبقة لـ OpenAI",
"text gen webio(ooba) presets": "الإعدادات المسبقة لـ WebUI(ooba)",
"response legth(tokens)": "طول الاستجابة (بعدد الاحرف او الرموز)",
@ -62,7 +61,7 @@
"Temperature": "درجة الحرارة",
"Frequency Penalty": "عقوبة التكرار",
"Presence Penalty": "عقوبة الوجود",
"Top-p": "أعلى p",
"Top-p": "أعلى p",
"Display bot response text chunks as they are generated": "عرض النصوص لجظة بلحظة",
"Top A": "أعلى A",
"Typical Sampling": "عينة نموذجية",
@ -101,7 +100,7 @@
"Inserts jailbreak as a last system message.": "يدرج كسر الحظر كرسالة نظام أخيرة.",
"This tells the AI to ignore its usual content restrictions.": "هذا يخبر الذكاء الاصطناعي بتجاهل القيود المعتادة على المحتوى.",
"NSFW Encouraged": "NSFW مشجع",
"Tell the AI that NSFW is allowed.": "قل للذكاء الاصطناعي أنه يُسمح بـ NSFW",
"Tell the AI that NSFW is allowed.": "قل للذكاء الاصطناعي أنه يُسمح بـ NSFW",
"NSFW Prioritized": "الأولوية للمحتوى غير مناسب للعمل",
"NSFW prompt text goes first in the prompt to emphasize its effect.": "النص الغير مناسب للعمل يأتي أولاً في التعليمات لتأكيد تأثيره.",
"Streaming": "البث المباشر ل",
@ -141,7 +140,7 @@
"Influences bot behavior in its responses": "يؤثر على سلوك الروبوت في ردوده.",
"Connect": "الاتصال",
"Test Message": "رسالة اختبار",
"API": "واجهة برمجة التطبيقات (API)",
"API": "واجهة برمجة التطبيقات (API)",
"KoboldAI": "KoboldAI",
"Use Horde": "استخدام Horde",
"API url": "رابط API",
@ -206,7 +205,7 @@
"Scale API Key": "مفتاح API لـ Scale",
"Alt Method": "طريقة بديلة",
"AI21 API Key": "مفتاح API لـ AI21",
"AI21 Model": "نموذج AI21",
"AI21 Model": "نموذج AI21",
"View API Usage Metrics": "عرض مقاييس استخدام واجهة برمجة التطبيقات",
"Show External models (provided by API)": "عرض النماذج الخارجية (المقدمة من قبل واجهة برمجة التطبيقات)",
"Bot": "روبوت:",
@ -495,7 +494,6 @@
"Global Lore First": "سرد العالم أولاً",
"Recursive Scan": "فحص متكرر",
"Case Sensitive": "حساس لحالة الأحرف",
"Match whole words": "تطابق الكلمات الكاملة",
"Alert On Overflow": "تنبيه عند التجاوز",
"World/Lore Editor": "محرر العالم/السرد",
"--- None ---": "--- لا شيء ---",
@ -915,7 +913,7 @@
"Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "استخدم المحلل النحوي المناسب لنماذج Google عبر واجهة برمجة التطبيقات الخاصة بهم. معالجة الإشارات الأولية بطيئة، ولكنها تقدم عداد رمز دقيق جدًا.",
"Load koboldcpp order": "تحميل أمر koboldcpp",
"Use Google Tokenizer": "استخدم محلل النحوي من Google"
}
}

View File

@ -3,7 +3,6 @@
"kobldpresets": "Kobold-Einstellungen von vorher",
"guikoboldaisettings": "KoboldAI-Einstellungen für das Menü",
"novelaipreserts": "NovelAI-Einstellungen von früher",
"default": "Normal",
"openaipresets": "OpenAI-Einstellungen von vorher",
"text gen webio(ooba) presets": "WebUI(ooba)-Einstellungen für Texterstellung",
"response legth(tokens)": "Länge der Antwort (Tokens)",
@ -494,7 +493,6 @@
"Global Lore First": "Globale Lore zuerst",
"Recursive Scan": "Rekursive Suche",
"Case Sensitive": "Groß-/Kleinschreibung beachten",
"Match whole words": "Ganze Wörter abgleichen",
"Alert On Overflow": "Warnung bei Überlauf",
"World/Lore Editor": "Welt-/Lore-Editor",
"--- None ---": "--- Keine ---",
@ -917,5 +915,5 @@
}
}

View File

@ -3,7 +3,6 @@
"kobldpresets": "Preajustes de Kobold",
"guikoboldaisettings": "Ajustes de interfaz de KoboldAI",
"novelaipreserts": "Preajustes de NovelAI",
"default": "Predeterminado",
"openaipresets": "Preajustes de OpenAI",
"text gen webio(ooba) presets": "Preajustes de Text Gen WebUI(ooba)",
"response legth(tokens)": "Longitud de respuesta (tokens)",
@ -494,7 +493,6 @@
"Global Lore First": "Historia Global Primero",
"Recursive Scan": "Escaneo Recursiva",
"Case Sensitive": "Sensible a mayúsculas y minúsculas",
"Match whole words": "Coincidir palabras completas",
"Alert On Overflow": "Alerta en Desbordamiento",
"World/Lore Editor": "Editor de Mundo/Historia",
"--- None ---": "--- Ninguno ---",
@ -891,6 +889,7 @@
"Chat API": " API de chat",
"and pick a character": "y elige un personaje",
"in the chat bar": "en la barra de chat",
"You can browse a list of bundled characters in the Download Extensions & Assets menu within": "Puedes explorar una lista de personajes incluidos en el menú de Download Extensions & Assets dentro de ",
"Confused or lost?": "¿Confundido o perdido?",
"click these icons!": "¡Haz clic en estos iconos!",
"SillyTavern Documentation Site": "Sitio de documentación de SillyTavern",
@ -914,7 +913,4 @@
"Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Usa el tokenizador apropiado para los modelos de Google a través de su API. Procesamiento de indicaciones más lento, pero ofrece un recuento de tokens mucho más preciso.",
"Load koboldcpp order": "Cargar orden de koboldcpp",
"Use Google Tokenizer": "Usar Tokenizador de Google"
}

View File

@ -3,7 +3,6 @@
"kobldpresets": "Préréglages de Kobold",
"guikoboldaisettings": "Paramètres de l'interface utilisateur de KoboldAI",
"novelaipreserts": "Préréglages de NovelAI",
"default": "Par défaut",
"openaipresets": "Préréglages d'OpenAI",
"text gen webio(ooba) presets": "Préréglages de WebUI(ooba)",
"response legth(tokens)": "Longueur de la réponse (en tokens)",
@ -205,7 +204,7 @@
"Scale API Key": "Clé API Scale",
"Alt Method": "Méthode alternative",
"AI21 API Key": "Clé API AI21",
"AI21 Model": "Modèle AI21",
"AI21 Model": "Modèle AI21",
"View API Usage Metrics": "Afficher les mesures d'utilisation de l'API",
"Show External models (provided by API)": "Afficher les modèles externes (fournis par l'API)",
"Bot": "Bot",
@ -494,7 +493,6 @@
"Global Lore First": "Lore global d'abord",
"Recursive Scan": "Analyse récursive",
"Case Sensitive": "Sensible à la casse",
"Match whole words": "Correspondre aux mots entiers",
"Alert On Overflow": "Alerte en cas de dépassement",
"World/Lore Editor": "Éditeur de monde/lore",
"--- None ---": "--- Aucun ---",
@ -914,5 +912,5 @@
"Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Utilisez le tokenizer approprié pour les modèles Google via leur API. Traitement des invitations plus lent, mais offre un décompte de jetons beaucoup plus précis.",
"Load koboldcpp order": "Charger l'ordre koboldcpp",
"Use Google Tokenizer": "Utiliser le tokenizer Google"
}
}

View File

@ -3,7 +3,6 @@
"kobldpresets": "Fyrir stillingar Kobold",
"guikoboldaisettings": "Stillingar fyrir KoboldAI viðmót",
"novelaipreserts": "Fyrir stillingar NovelAI",
"default": "Sjálfgefið",
"openaipresets": "Fyrir stillingar OpenAI",
"text gen webio(ooba) presets": "Fyrir stillingar WebUI(ooba) textagerðar",
"response legth(tokens)": "Lengd svars (í táknum eða stöfum)",
@ -62,7 +61,7 @@
"Temperature": "Hitastig",
"Frequency Penalty": "Tíðnarefning",
"Presence Penalty": "Tilkoma refning",
"Top-p": "Topp-p",
"Top-p": "Topp-p",
"Display bot response text chunks as they are generated": "Birta bætir svarborðstextabrot þegar þau eru búnar til",
"Top A": "Topp A",
"Typical Sampling": "Venjuleg úrtaka",
@ -495,7 +494,6 @@
"Global Lore First": "Fyrst heimsfræði",
"Recursive Scan": "Endurkvæm skoðun",
"Case Sensitive": "Skilgreiningarfræðilegt",
"Match whole words": "Nákvæm samræmi",
"Alert On Overflow": "Viðvörun um flæði",
"World/Lore Editor": "Heims-/fræðiritari",
"--- None ---": "--- Engin ---",
@ -915,5 +913,5 @@
"Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Notaðu rétta tokenizer fyrir Google módel með þeirra API. Hægri umhvörf fyrir hvöttavinnslu, en býður upp á miklu nákvæmari talningu á táknunum.",
"Load koboldcpp order": "Hlaðið inn færslu af koboldcpp",
"Use Google Tokenizer": "Notaðu Google Tokenizer"
}
}

View File

@ -3,7 +3,6 @@
"kobldpresets": "Preimpostazioni Kobold",
"guikoboldaisettings": "Impostazioni dell'interfaccia KoboldAI",
"novelaipreserts": "Preimpostazioni NovelAI",
"default": "Predefinito",
"openaipresets": "Preimpostazioni OpenAI",
"text gen webio(ooba) presets": "Preimpostazioni WebUI(ooba) per la generazione di testo",
"response legth(tokens)": "Lunghezza della risposta (token)",
@ -495,7 +494,6 @@
"Global Lore First": "Lore Globale Prima",
"Recursive Scan": "Scansione Ricorsiva",
"Case Sensitive": "Sensibile alle Maiuscole",
"Match whole words": "Corrispondi a parole intere",
"Alert On Overflow": "Avviso Su Overflow",
"World/Lore Editor": "Editor di Mondo/Lore",
"--- None ---": "--- Nessuno ---",
@ -917,5 +915,5 @@
"Use Google Tokenizer": "Usa il Tokenizer di Google"
}
}

View File

@ -3,7 +3,6 @@
"kobldpresets": "Koboldのプリセット",
"guikoboldaisettings": "KoboldAIのGUI設定",
"novelaipreserts": "NovelAIのプリセット",
"default": "デフォルト",
"openaipresets": "OpenAIのプリセット",
"text gen webio(ooba) presets": "WebUI(ooba)のプリセット",
"response legth(tokens)": "応答の長さ(トークン数)",
@ -140,7 +139,7 @@
"Influences bot behavior in its responses": "返信でボットの動作に影響を与えます",
"Connect": "接続",
"Test Message": "テストメッセージ",
"API": "API",
"API": "API",
"KoboldAI": "KoboldAI",
"Use Horde": "ホードを使用",
"API url": "API URL",
@ -494,7 +493,6 @@
"Global Lore First": "グローバルロアを最初に表示",
"Recursive Scan": "再帰的スキャン",
"Case Sensitive": "大文字と小文字を区別する",
"Match whole words": "完全な単語の一致",
"Alert On Overflow": "オーバーフロー時に警告",
"World/Lore Editor": "ワールド/ロアの編集",
"--- None ---": "--- なし ---",
@ -914,5 +912,5 @@
"Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Googleモデル用の適切なトークナイザーを使用します。 API経由で。 処理が遅くなりますが、トークンの数え上げがはるかに正確になります。",
"Load koboldcpp order": "koboldcppオーダーを読み込む",
"Use Google Tokenizer": "Googleトークナイザーを使用"
}
}

View File

@ -3,7 +3,6 @@
"kobldpresets": "코볼드 사전 설정",
"guikoboldaisettings": "KoboldAI 인터페이스 설정",
"novelaipreserts": "NovelAI 사전 설정",
"default": "기본값",
"openaipresets": "OpenAI 사전 설정",
"text gen webio(ooba) presets": "텍스트 생성 WebUI(ooba) 사전 설정",
"response legth(tokens)": "응답 길이 (토큰)",
@ -495,7 +494,6 @@
"Global Lore First": "글로벌 로어 우선",
"Recursive Scan": "재귀 스캔",
"Case Sensitive": "대소문자 구분",
"Match whole words": "전체 단어 일치",
"Alert On Overflow": "오버플로우 알림",
"World/Lore Editor": "월드/로어 편집기",
"--- None ---": "--- 없음 ---",
@ -939,5 +937,5 @@
"Account": "계정",
"Theme Colors": "테마 색상",
"# Messages to Load": "로딩할 메시지 수"
}
}

View File

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

View File

@ -3,7 +3,6 @@
"kobldpresets": "Kobold voorinstellingen",
"guikoboldaisettings": "KoboldAI-interface-instellingen",
"novelaipreserts": "NovelAI-voorinstellingen",
"default": "Standaard",
"openaipresets": "OpenAI-voorinstellingen",
"text gen webio(ooba) presets": "WebUI(ooba)-voorinstellingen voor tekstgeneratie",
"response legth(tokens)": "Reactielengte (tokens)",
@ -495,7 +494,6 @@
"Global Lore First": "Globale Lore Eerst",
"Recursive Scan": "Recursieve Scan",
"Case Sensitive": "Hoofdlettergevoelig",
"Match whole words": "Hele woorden matchen",
"Alert On Overflow": "Waarschuwing bij overloop",
"World/Lore Editor": "Wereld/Lore Editor",
"--- None ---": "--- Geen ---",
@ -917,5 +915,5 @@
"Use Google Tokenizer": "Google Tokenizer gebruiken"
}
}

View File

@ -3,7 +3,6 @@
"kobldpresets": "Configurações predefinidas do Kobold",
"guikoboldaisettings": "Configurações da interface do KoboldAI",
"novelaipreserts": "Configurações predefinidas do NovelAI",
"default": "Padrão",
"openaipresets": "Configurações predefinidas do OpenAI",
"text gen webio(ooba) presets": "Configurações predefinidas do WebUI(ooba) para geração de texto",
"response legth(tokens)": "Comprimento da resposta (tokens)",
@ -493,7 +492,6 @@
"Global Lore First": "Lore Global Primeiro",
"Recursive Scan": "Verificação Recursiva",
"Case Sensitive": "Sensível a Maiúsculas",
"Match whole words": "Corresponder palavras inteiras",
"Alert On Overflow": "Alerta em Overflow",
"World/Lore Editor": "Editor de Mundo/Lore",
"--- None ---": "--- Nenhum ---",
@ -915,5 +913,5 @@
"Use Google Tokenizer": "Usar Tokenizer do Google"
}
}

View File

@ -3,7 +3,6 @@
"kobldpresets": "Пресеты для Kobold",
"guikoboldaisettings": "Настройки из интерфейса KoboldAI",
"novelaipreserts": "Пресеты для NovelAI",
"default": "По умолчанию",
"openaipresets": "Пресеты для OpenAI",
"text gen webio(ooba) presets": "Пресеты для WebUI(ooba)",
"response legth(tokens)": "Ответ (в токенах)",
@ -276,7 +275,7 @@
"World Info": "Информация о мире",
"Scan Depth": "Глубина сканирования",
"Case-Sensitive": "С учетом регистра",
"Match Whole Words": "Только целые слова",
"Match Whole Words": "Только полное совпадение",
"Use global setting": "Использовать глобальную настройку",
"Yes": "Да",
"No": "Нет",
@ -495,7 +494,6 @@
"Global Lore First": "Сначала глобальный лор",
"Recursive Scan": "Рекурсивное сканирование",
"Case Sensitive": "Учитывать регистр",
"Match whole words": "Только полное совпадение",
"Alert On Overflow": "Оповещение о переполнении",
"World/Lore Editor": "Редактировать мир или лор",
"--- None ---": "--- Отсутствует ---",

View File

@ -3,7 +3,6 @@
"kobldpresets": "Налаштування Kobold",
"guikoboldaisettings": "З інтерфейсу KoboldAI",
"novelaipreserts": "Налаштування NovelAI",
"default": "За замовчуванням",
"openaipresets": "Налаштування OpenAI",
"text gen webio(ooba) presets": "Налаштування Text Completion",
"response legth(tokens)": "Відповідь (токени)",
@ -495,7 +494,6 @@
"Global Lore First": "Глобальна інформація першою",
"Recursive Scan": "Рекурсивне сканування",
"Case Sensitive": "Чутливість до регістру",
"Match whole words": "Відповідність цілим словам",
"Alert On Overflow": "Сповіщення при переповненні",
"World/Lore Editor": "Редактор світу/книги",
"--- None ---": "--- Нічого ---",

View File

@ -3,7 +3,6 @@
"kobldpresets": "Cài đặt trước Kobold",
"guikoboldaisettings": "Cài đặt giao diện KoboldAI",
"novelaipreserts": "Cài đặt trước NovelAI",
"default": "Mặc định",
"openaipresets": "Cài đặt trước OpenAI",
"text gen webio(ooba) presets": "Cài đặt trước WebUI(ooba) của máy tạo văn bản",
"response legth(tokens)": "Độ dài phản hồi (trong các token)",
@ -62,7 +61,7 @@
"Temperature": "Nhiệt độ",
"Frequency Penalty": "Phạt Tần số",
"Presence Penalty": "Phạt Sự hiện",
"Top-p": "Top-p",
"Top-p": "Top-p",
"Display bot response text chunks as they are generated": "Hiển thị các phần văn bản phản hồi của bot khi chúng được tạo ra",
"Top A": "Top A",
"Typical Sampling": "Mẫu Đại diện",
@ -141,7 +140,7 @@
"Influences bot behavior in its responses": "Ảnh hưởng đến hành vi của bot trong các phản hồi của nó",
"Connect": "Kết nối",
"Test Message": "Tin nhắn kiểm tra",
"API": "Giao diện lập trình ứng dụng (API)",
"API": "Giao diện lập trình ứng dụng (API)",
"KoboldAI": "KoboldAI",
"Use Horde": "Sử dụng Horde",
"API url": "URL API",
@ -206,7 +205,7 @@
"Scale API Key": "Khóa API của Scale",
"Alt Method": "Phương pháp thay thế",
"AI21 API Key": "Khóa API của AI21",
"AI21 Model": "Mô hình AI21",
"AI21 Model": "Mô hình AI21",
"View API Usage Metrics": "Xem số liệu sử dụng API",
"Show External models (provided by API)": "Hiển thị các mô hình bên ngoài (do API cung cấp)",
"Bot": "Bot:",
@ -495,7 +494,6 @@
"Global Lore First": "Sử liệu toàn cầu đầu tiên",
"Recursive Scan": "Quét đệ quy",
"Case Sensitive": "Phân biệt chữ hoa chữ thường",
"Match whole words": "Khớp toàn bộ từ",
"Alert On Overflow": "Cảnh báo khi tràn",
"World/Lore Editor": "Trình soạn thảo Thế giới/Sử liệu",
"--- None ---": "--- Không ---",
@ -915,5 +913,5 @@
"Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Sử dụng bộ mã hóa phù hợp cho các mô hình của Google thông qua API của họ. Xử lý lời mời chậm hơn, nhưng cung cấp đếm token chính xác hơn nhiều.",
"Load koboldcpp order": "Tải đơn hàng koboldcpp",
"Use Google Tokenizer": "Sử dụng bộ mã hóa của Google"
}
}

View File

@ -3,7 +3,6 @@
"kobldpresets": "Kobold 预设",
"guikoboldaisettings": "KoboldAI 用户界面设置",
"novelaipreserts": "NovelAI 预设",
"default": "默认",
"openaipresets": "对话补全预设",
"text gen webio(ooba) presets": "WebUI(ooba) 预设",
"response legth(tokens)": "响应长度(以词符数计)",
@ -495,7 +494,6 @@
"Global Lore First": "全局世界书优先",
"Recursive Scan": "递归扫描",
"Case Sensitive": "区分大小写",
"Match whole words": "完整匹配单词",
"Alert On Overflow": "溢出警报",
"World/Lore Editor": "世界书编辑器",
"--- None ---": "--- 无 ---",

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

File diff suppressed because it is too large Load Diff

View File

@ -8636,11 +8636,6 @@ jQuery(async function () {
callback: doCloseChat,
helpString: 'Closes the current chat.',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'closechat',
callback: doCloseChat,
helpString: 'Closes the current chat.',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'panels',
callback: doTogglePanels,
aliases: ['togglepanels'],

View File

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

View File

@ -7,7 +7,7 @@
Don't include the page name!
</i>
<small>
<span data-i18n=Examples:">Examples:</span>
<span data-i18n="Examples:">Examples:</span>
<code>https://streetcat.wiki/index.php</code>
<span data-i18n="or">or</span>
<code>https://tcrf.net</code>

View File

@ -342,6 +342,16 @@ export class QuickReply {
message.addEventListener('scroll', (evt)=>{
updateScrollDebounced();
});
/** @type {any} */
const resizeListener = debounce((evt) => {
updateSyntax();
updateScrollDebounced(evt);
if (document.activeElement == message) {
message.blur();
message.focus();
}
});
window.addEventListener('resize', resizeListener);
message.style.color = 'transparent';
message.style.background = 'transparent';
message.style.setProperty('text-shadow', 'none', 'important');
@ -514,6 +524,8 @@ export class QuickReply {
});
await popupResult;
window.removeEventListener('resize', resizeListener);
} else {
warn('failed to fetch qrEditor template');
}

View File

@ -266,6 +266,7 @@ const default_settings = {
show_external_models: false,
proxy_password: '',
assistant_prefill: '',
assistant_impersonation: '',
human_sysprompt_message: default_claude_human_sysprompt_message,
use_ai21_tokenizer: false,
use_google_tokenizer: false,
@ -342,6 +343,7 @@ const oai_settings = {
show_external_models: false,
proxy_password: '',
assistant_prefill: '',
assistant_impersonation: '',
human_sysprompt_message: default_claude_human_sysprompt_message,
use_ai21_tokenizer: false,
use_google_tokenizer: false,
@ -1767,7 +1769,7 @@ async function sendOpenAIRequest(type, messages, signal) {
generate_data['human_sysprompt_message'] = substituteParams(oai_settings.human_sysprompt_message);
// Don't add a prefill on quiet gens (summarization)
if (!isQuiet) {
generate_data['assistant_prefill'] = substituteParams(oai_settings.assistant_prefill);
generate_data['assistant_prefill'] = isImpersonate ? substituteParams(oai_settings.assistant_impersonation) : substituteParams(oai_settings.assistant_prefill);
}
}
@ -2760,6 +2762,7 @@ function loadOpenAISettings(data, settings) {
oai_settings.show_external_models = settings.show_external_models ?? default_settings.show_external_models;
oai_settings.proxy_password = settings.proxy_password ?? default_settings.proxy_password;
oai_settings.assistant_prefill = settings.assistant_prefill ?? default_settings.assistant_prefill;
oai_settings.assistant_impersonation = settings.assistant_impersonation ?? default_settings.assistant_impersonation;
oai_settings.human_sysprompt_message = settings.human_sysprompt_message ?? default_settings.human_sysprompt_message;
oai_settings.image_inlining = settings.image_inlining ?? default_settings.image_inlining;
oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality;
@ -2796,6 +2799,7 @@ function loadOpenAISettings(data, settings) {
$('#api_url_scale').val(oai_settings.api_url_scale);
$('#openai_proxy_password').val(oai_settings.proxy_password);
$('#claude_assistant_prefill').val(oai_settings.assistant_prefill);
$('#claude_assistant_impersonation').val(oai_settings.assistant_impersonation);
$('#claude_human_sysprompt_textarea').val(oai_settings.human_sysprompt_message);
$('#openai_image_inlining').prop('checked', oai_settings.image_inlining);
$('#openai_bypass_status_check').prop('checked', oai_settings.bypass_status_check);
@ -3115,6 +3119,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
api_url_scale: settings.api_url_scale,
show_external_models: settings.show_external_models,
assistant_prefill: settings.assistant_prefill,
assistant_impersonation: settings.assistant_impersonation,
human_sysprompt_message: settings.human_sysprompt_message,
use_ai21_tokenizer: settings.use_ai21_tokenizer,
use_google_tokenizer: settings.use_google_tokenizer,
@ -3501,6 +3506,7 @@ function onSettingsPresetChange() {
show_external_models: ['#openai_show_external_models', 'show_external_models', true],
proxy_password: ['#openai_proxy_password', 'proxy_password', false],
assistant_prefill: ['#claude_assistant_prefill', 'assistant_prefill', false],
assistant_impersonation: ['#claude_assistant_impersonation', 'assistant_impersonation', false],
human_sysprompt_message: ['#claude_human_sysprompt_textarea', 'human_sysprompt_message', false],
use_ai21_tokenizer: ['#use_ai21_tokenizer', 'use_ai21_tokenizer', true],
use_google_tokenizer: ['#use_google_tokenizer', 'use_google_tokenizer', true],
@ -3526,6 +3532,11 @@ function onSettingsPresetChange() {
preset.names_behavior = character_names_behavior.COMPLETION;
}
// Claude: Assistant Impersonation Prefill = Inherit from Assistant Prefill
if (preset.assistant_prefill !== undefined && preset.assistant_impersonation === undefined) {
preset.assistant_impersonation = preset.assistant_prefill;
}
const updateInput = (selector, value) => $(selector).val(value).trigger('input');
const updateCheckbox = (selector, value) => $(selector).prop('checked', value).trigger('input');
@ -4721,6 +4732,11 @@ $(document).ready(async function () {
saveSettingsDebounced();
});
$('#claude_assistant_impersonation').on('input', function () {
oai_settings.assistant_impersonation = String($(this).val());
saveSettingsDebounced();
});
$('#claude_human_sysprompt_textarea').on('input', function () {
oai_settings.human_sysprompt_message = String($('#claude_human_sysprompt_textarea').val());
saveSettingsDebounced();

View File

@ -114,7 +114,9 @@ class PresetManager {
* @returns {any} Preset value
*/
findPreset(name) {
return $(this.select).find(`option:contains(${name})`).val();
return $(this.select).find('option').filter(function() {
return $(this).text() === name;
}).val();
}
/**

View File

@ -447,8 +447,9 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'unhide',
],
helpString: 'Unhides a message from the prompt.',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'disable',
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-disable',
callback: disableGroupMemberCallback,
aliases: ['disable', 'disablemember', 'memberdisable'],
unnamedArgumentList: [
new SlashCommandArgument(
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
@ -456,7 +457,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'disable',
],
helpString: 'Disables a group member from being drafted for replies.',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'enable',
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-enable',
aliases: ['enable', 'enablemember', 'memberenable'],
callback: enableGroupMemberCallback,
unnamedArgumentList: [
new SlashCommandArgument(
@ -465,9 +467,9 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'enable',
],
helpString: 'Enables a group member to be drafted for replies.',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'memberadd',
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-add',
callback: addGroupMemberCallback,
aliases: ['addmember'],
aliases: ['addmember', 'memberadd'],
unnamedArgumentList: [
new SlashCommandArgument(
'character name', [ARGUMENT_TYPE.STRING], true,
@ -481,15 +483,15 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'memberadd',
<strong>Example:</strong>
<ul>
<li>
<pre><code>/memberadd John Doe</code></pre>
<pre><code>/member-add John Doe</code></pre>
</li>
</ul>
</div>
`,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'memberremove',
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-remove',
callback: removeGroupMemberCallback,
aliases: ['removemember'],
aliases: ['removemember', 'memberremove'],
unnamedArgumentList: [
new SlashCommandArgument(
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
@ -503,16 +505,16 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'memberremove
<strong>Example:</strong>
<ul>
<li>
<pre><code>/memberremove 2</code></pre>
<pre><code>/memberremove John Doe</code></pre>
<pre><code>/member-remove 2</code></pre>
<pre><code>/member-remove John Doe</code></pre>
</li>
</ul>
</div>
`,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'memberup',
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-up',
callback: moveGroupMemberUpCallback,
aliases: ['upmember'],
aliases: ['upmember', 'memberup'],
unnamedArgumentList: [
new SlashCommandArgument(
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
@ -520,9 +522,9 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'memberup',
],
helpString: 'Moves a group member up in the group chat list.',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'memberdown',
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'member-down',
callback: moveGroupMemberDownCallback,
aliases: ['downmember'],
aliases: ['downmember', 'memberdown'],
unnamedArgumentList: [
new SlashCommandArgument(
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
@ -1421,7 +1423,7 @@ async function runCallback(args, name) {
function abortCallback() {
$('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles:true }));
throw new Error('/abort command executed');
throw new Error('/abort command executed', { cause: 'abort' });
}
async function delayCallback(_, amount) {
@ -2747,10 +2749,12 @@ export async function executeSlashCommandsOnChatInput(text, options = {}) {
}
} catch (e) {
document.querySelector('#form_sheld').classList.add('script_error');
toastr.error(e.message);
result = new SlashCommandClosureResult();
result.isError = true;
result.errorMessage = e.message;
if (e.cause !== 'abort') {
toastr.error(e.message);
}
} finally {
delay(1000).then(()=>clearCommandProgressDebounced());

View File

@ -58,6 +58,9 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
return new RegExp('=(.*)');
}
}
if (!Array.isArray(this.executor.command?.namedArgumentList)) {
return null;
}
const notProvidedNamedArguments = this.executor.command.namedArgumentList.filter(arg=>!this.executor.namedArgumentList.find(it=>it.name == arg.name));
let name;
let value;
@ -130,6 +133,9 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
}
getUnnamedArgumentAt(text, index, isSelect) {
if (!Array.isArray(this.executor.command?.unnamedArgumentList)) {
return null;
}
const lastArgIsBlank = this.executor.unnamedArgumentList.slice(-1)[0]?.value == '';
const notProvidedArguments = this.executor.command.unnamedArgumentList.slice(this.executor.unnamedArgumentList.length - (lastArgIsBlank ? 1 : 0));
let value;

View File

@ -14,7 +14,7 @@ import {
// eslint-disable-next-line no-unused-vars
import { FILTER_TYPES, FILTER_STATES, DEFAULT_FILTER_STATE, isFilterState, FilterHelper } from './filters.js';
import { groupCandidatesFilter, groups, selected_group } from './group-chats.js';
import { groupCandidatesFilter, groups, select_group_chats, selected_group } from './group-chats.js';
import { download, onlyUnique, parseJsonFile, uuidv4, getSortableDelay, flashHighlight } from './utils.js';
import { power_user } from './power-user.js';
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
@ -707,7 +707,7 @@ function createNewTag(tagName) {
create_date: Date.now(),
};
tags.push(tag);
console.debug('Created new tag', tag.name, 'with id', id);
console.debug('Created new tag', tag.name, 'with id', tag.id);
return tag;
}
@ -1047,7 +1047,7 @@ function onGroupCreateClick() {
export function applyTagsOnCharacterSelect() {
//clearTagsFilter();
const chid = Number($(this).attr('chid'));
const chid = Number(this_chid);
printTagList($('#tagList'), { forEntityOrKey: chid, tagOptions: { removable: true } });
}
@ -1530,7 +1530,9 @@ function registerTagsSlashCommands() {
* @returns {string?} - The char/group key, or null if none found
*/
function paraGetCharKey(charName) {
const entity = charName ? characters.find(x => x.name === charName) || groups.find(x => x.name == charName) : characters[this_chid] || groups[selected_group];
const entity = charName
? (characters.find(x => x.name === charName) || groups.find(x => x.name == charName))
: (selected_group ? groups.find(x => x.id == selected_group) : characters[this_chid]);
const key = getTagKeyForEntity(entity);
if (!key) {
toastr.warning(`Character ${charName} not found.`);
@ -1547,7 +1549,7 @@ function registerTagsSlashCommands() {
*/
function paraGetTag(tagName, { allowCreate = false } = {}) {
if (!tagName) {
toastr.warning(`Tag name must be provided.`);
toastr.warning('Tag name must be provided.');
return null;
}
let tag = tags.find(t => t.name === tagName);
@ -1561,6 +1563,21 @@ function registerTagsSlashCommands() {
return tag;
}
function updateTagsList() {
switch (menu_type) {
case 'characters':
printTagFilters(tag_filter_types.character);
printTagFilters(tag_filter_types.group_member);
break;
case 'character_edit':
applyTagsOnCharacterSelect();
break;
case 'group_edit':
select_group_chats(selected_group, true);
break;
}
}
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'tag-add',
returns: 'true/false - Whether the tag was added or was assigned already',
@ -1571,6 +1588,7 @@ function registerTagsSlashCommands() {
const tag = paraGetTag(tagName, { allowCreate: true });
if (!tag) return 'false';
const result = addTagToEntity(tag, key);
updateTagsList();
return String(result);
},
namedArgumentList: [
@ -1605,6 +1623,7 @@ function registerTagsSlashCommands() {
const tag = paraGetTag(tagName);
if (!tag) return 'false';
const result = removeTagFromEntity(tag, key);
updateTagsList();
return String(result);
},
namedArgumentList: [
@ -1698,8 +1717,6 @@ export function initTags() {
$(document).on('click', '#rm_button_create', onCharacterCreateClick);
$(document).on('click', '#rm_button_group_chats', onGroupCreateClick);
$(document).on('click', '.character_select', applyTagsOnCharacterSelect);
$(document).on('click', '.group_select', applyTagsOnGroupSelect);
$(document).on('click', '.tag_remove', onTagRemoveClick);
$(document).on('input', '.tag_input', onTagInput);
$(document).on('click', '.tags_view', onViewTagsListClick);
@ -1710,6 +1727,7 @@ export function initTags() {
$(document).on('click', '.tag_view_backup', onTagsBackupClick);
$(document).on('click', '.tag_view_restore', onBackupRestoreClick);
eventSource.on(event_types.CHARACTER_DUPLICATED, copyTags);
eventSource.makeFirst(event_types.CHAT_CHANGED, () => selected_group ? applyTagsOnGroupSelect() : applyTagsOnCharacterSelect());
$(document).on('input', '#dialogue_popup input[name="auto_sort_tags"]', (evt) => {
const toggle = $(evt.target).is(':checked');

View File

@ -11,9 +11,10 @@
<span data-i18n="Click ">Click </span><code><i class="fa-solid fa-plug"></i></code><span data-i18n="and select a"> and select a </span><a href="https://docs.sillytavern.app/usage/api-connections/" target="_blank" data-i18n="Chat API">Chat API</a>.</span>
</li>
<li>
<span data-i18n="Click ">Click </span><code><i class="fa-solid fa-address-card"></i></code><span data-i18n="and pick a character"> and pick a character</span>
<span data-i18n="Click ">Click </span><code><i class="fa-solid fa-address-card"></i></code><span data-i18n="and pick a character."> and pick a character.</span>
</li>
</ol>
<span data-i18n="You can browse a list of bundled characters in the Download Extensions & Assets menu within">You can browse a list of bundled characters in the <i>Download Extensions & Assets</i> menu within </span><code><i class="fa-solid fa-cubes"></i></code><span>.</span>
<hr>
<h3 data-i18n="Confused or lost?">Confused or lost?</h3>
<ul>

View File

@ -518,7 +518,7 @@ async function executeSubCommands(command, scope = null, parserFlags = null) {
command = command.slice(1, -1);
}
const result = await executeSlashCommands(command, true, scope, true, parserFlags);
const result = await executeSlashCommands(command, true, scope, false, parserFlags);
if (!result || typeof result !== 'object') {
return '';

View File

@ -1,5 +1,5 @@
import { saveSettings, callPopup, substituteParams, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types, getExtensionPromptByName, saveMetadata, getCurrentChatId, extension_prompt_roles } from '../script.js';
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight, select2ModifyOptions, getSelect2OptionId, dynamicSelect2DataViaAjax, highlightRegex, select2ChoiceClickSubscribe } from './utils.js';
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight, select2ModifyOptions, getSelect2OptionId, dynamicSelect2DataViaAjax, highlightRegex, select2ChoiceClickSubscribe, isFalseBoolean } from './utils.js';
import { extension_settings, getContext } from './extensions.js';
import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from './authors-note.js';
import { isMobile } from './RossAscends-mods.js';
@ -548,6 +548,19 @@ function registerWorldInfoSlashCommands() {
return '';
}
if (typeof newEntryTemplate[field] === 'boolean') {
const isTrue = isTrueBoolean(value);
const isFalse = isFalseBoolean(value);
if (isTrue) {
value = String(true);
}
if (isFalse) {
value = String(false);
}
}
const fuse = new Fuse(entries, {
keys: [{ name: field, weight: 1 }],
includeScore: true,
@ -1244,6 +1257,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
}
worldEntriesList.sortable({
items: '.world_entry',
delay: getSortableDelay(),
handle: '.drag-handle',
stop: async function (_event, _ui) {

View File

@ -2068,6 +2068,7 @@ input[type="file"] {
gap: 5px;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
.bulk_select_checkbox {
@ -4892,4 +4893,4 @@ body:not(.movingUI) .drawer-content.maximized {
.regex-operator { color: #FFB6C1; } /* Light Pink */
.regex-flags { color: #98FB98; } /* Pale Green */
.regex-delimiter { font-weight: bold; color: #FF6961; } /* Pastel Red */
.regex-highlight { color: #FAF8F6; } /* Pastel White */
.regex-highlight { color: #FAF8F6; } /* Pastel White */

View File

@ -7,7 +7,9 @@ const { getConfigValue, color } = require('../util');
const { jsonParser } = require('../express-common');
const writeFileAtomicSync = require('write-file-atomic').sync;
const contentDirectory = path.join(process.cwd(), 'default/content');
const scaffoldDirectory = path.join(process.cwd(), 'default/scaffold');
const contentIndexPath = path.join(contentDirectory, 'index.json');
const scaffoldIndexPath = path.join(scaffoldDirectory, 'index.json');
const characterCardParser = require('../character-card-parser.js');
const WHITELIST_GENERIC_URL_DOWNLOAD_SOURCES = getConfigValue('whitelistImportDomains', []);
@ -16,6 +18,8 @@ const WHITELIST_GENERIC_URL_DOWNLOAD_SOURCES = getConfigValue('whitelistImportDo
* @typedef {Object} ContentItem
* @property {string} filename
* @property {string} type
* @property {string} [name]
* @property {string|null} [folder]
*/
/**
@ -48,9 +52,7 @@ const CONTENT_TYPES = {
*/
function getDefaultPresets(directories) {
try {
const contentIndexText = fs.readFileSync(contentIndexPath, 'utf8');
const contentIndex = JSON.parse(contentIndexText);
const contentIndex = getContentIndex();
const presets = [];
for (const contentItem of contentIndex) {
@ -112,8 +114,12 @@ async function seedContentForUser(contentIndex, directories, forceCategories) {
continue;
}
contentLog.push(contentItem.filename);
const contentPath = path.join(contentDirectory, contentItem.filename);
if (!contentItem.folder) {
console.log(`Content file ${contentItem.filename} has no parent folder`);
continue;
}
const contentPath = path.join(contentItem.folder, contentItem.filename);
if (!fs.existsSync(contentPath)) {
console.log(`Content file ${contentItem.filename} is missing`);
@ -129,6 +135,7 @@ async function seedContentForUser(contentIndex, directories, forceCategories) {
const basePath = path.parse(contentItem.filename).base;
const targetPath = path.join(contentTarget, basePath);
contentLog.push(contentItem.filename);
if (fs.existsSync(targetPath)) {
console.log(`Content file ${contentItem.filename} already exists in ${contentTarget}`);
@ -157,8 +164,7 @@ async function checkForNewContent(directoriesList, forceCategories = []) {
return;
}
const contentIndexText = fs.readFileSync(contentIndexPath, 'utf8');
const contentIndex = JSON.parse(contentIndexText);
const contentIndex = getContentIndex();
let anyContentAdded = false;
for (const directories of directoriesList) {
@ -179,6 +185,38 @@ async function checkForNewContent(directoriesList, forceCategories = []) {
}
}
/**
* Gets combined content index from the content and scaffold directories.
* @returns {ContentItem[]} Array of content index
*/
function getContentIndex() {
const result = [];
if (fs.existsSync(scaffoldIndexPath)) {
const scaffoldIndexText = fs.readFileSync(scaffoldIndexPath, 'utf8');
const scaffoldIndex = JSON.parse(scaffoldIndexText);
if (Array.isArray(scaffoldIndex)) {
scaffoldIndex.forEach((item) => {
item.folder = scaffoldDirectory;
});
result.push(...scaffoldIndex);
}
}
if (fs.existsSync(contentIndexPath)) {
const contentIndexText = fs.readFileSync(contentIndexPath, 'utf8');
const contentIndex = JSON.parse(contentIndexText);
if (Array.isArray(contentIndex)) {
contentIndex.forEach((item) => {
item.folder = contentDirectory;
});
result.push(...contentIndex);
}
}
return result;
}
/**
* Gets the target directory for the specified asset type.
* @param {ContentType} type Asset type