Merge branch 'staging' into frFr

5734722c5d050962953507f6edfd9cf554abf7e1

Cohee <18619528+Cohee1207@users.noreply.github.com>

29 files changed, +707 -209Ignore whitespace
public/index.html+10 -10
@@ -2278,7 +2278,7 @@
22782278 <h4 data-i18n="Model Providers">Model Providers</h4>
22792279 <select id="openrouter_providers_text" class="openrouter_providers" multiple>
22802280 </select>
22812281 <label class="checkbox_label" data-i18n="[title]Automatically chooses an alternative provider if chosen providers can't serve your request." for="openrouter_allow_fallbacks_textgenerationwebui" title="Automatically chooses an alternative provider if chosen providers can't serve your request.">
22822282 <input id="openrouter_allow_fallbacks_textgenerationwebui" type="checkbox" />
22832283 <span data-i18n="Allow fallback providers">Allow fallback providers</span>
22842284 </label>
@@ -2902,7 +2902,7 @@
29022902 <div>
29032903 <h4 data-i18n="Window AI Model">Window AI Model</h4>
29042904 <select id="model_windowai_select">
29052905 <option data-i18n="Use extension settings" value="">Use extension settings</option>
29062906 <option value="openai/gpt-3.5-turbo">openai/gpt-3.5-turbo</option>
29072907 <option value="openai/gpt-3.5-turbo-16k">openai/gpt-3.5-turbo-16k</option>
29082908 <option value="openai/gpt-4">openai/gpt-4</option>
@@ -2977,14 +2977,14 @@
29772977 <h4 data-i18n="Model Providers">Model Providers</h4>
29782978 <select id="openrouter_providers_chat" class="openrouter_providers" multiple>
29792979 </select>
29802980 <label class="checkbox_label marginTopBot5" for="openrouter_allow_fallbacks" data-i18n="[title]Automatically chooses an alternative provider if chosen providers can't serve your request." title="Automatically chooses an alternative provider if chosen providers can't serve your request.">
29812981 <input id="openrouter_allow_fallbacks" type="checkbox" />
29822982 <span data-i18n="Allow fallback providers">Allow fallback providers</span>
29832983 </label>
29842984 </div>
29852985 <small class="marginTopBot5">
29862986 <i class="fa-solid fa-lightbulb"></i>
29872987 <span data-i18n="To use instruct formatting, switch to OpenRouter under Text Completion API.">To use instruct formatting, switch to OpenRouter under Text Completion API.</span>
29882988 </small>
29892989 </form>
29902990 <form id="scale_form" data-source="scale" action="javascript:void(null);" method="post" enctype="multipart/form-data">
@@ -3319,7 +3319,7 @@
33193319 </div>
33203320 <h4 data-i18n="Enter a Model ID">Enter a Model ID</h4>
33213321 <div class="flex-container">
33223322 <input list="model_custom_select_fill" id="custom_model_id" class="text_pole wide100p" value="" autocomplete="off" data-i18n="[placeholder]Example: gpt-3.5-turbo4o" placeholder="Example: gpt-3.5-turbo4o">
33233323 <datalist id="model_custom_select_fill" class="text_pole model_custom_select"></datalist>
33243324 </div>
33253325 <h4 data-i18n="Available Models">Available Models</h4>
@@ -4601,7 +4601,7 @@
46014601 </div>
46024602 </div>
46034603 <div nane="AutoContiueBlock" class="inline-drawer wide100p flexFlowColumn">
46044604 <div class="inline-drawer-toggle inline-drawer-header userSettingsInnerExpandable" data-i18n="[title]Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens." title="Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.">
46054605 <b><span data-i18n="Auto-Continue">Auto-Continue</span></b>
46064606 <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
46074607 </div>
@@ -5734,7 +5734,7 @@
57345734 <span class="drag-handle">&#9776;</span>
57355735 <div class="gap5px world_entry_thin_controls wide100p alignitemscenter">
57365736 <div class="inline-drawer-toggle fa-fw fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
57375737 <div class="fa-solid fa-toggle-on killSwitch" name="entryKillSwitch" data-i18n="[title]Toggle entry's active state." title="Toggle entry's active state."></div>
57385738 <div class="flex-container alignitemscenter wide100p">
57395739 <div class="WIEntryTitleAndStatus flex-container flex1 alignitemscenter">
57405740 <div class="flex-container flex1">
@@ -5967,7 +5967,7 @@
59675967 </small>
59685968 </div>
59695969 <div class="range-block-range">
59705970 <input class="text_pole margin0" name="sticky" type="number" data-i18n="[placeholder]Non-sticky" placeholder="Non-sticky" min="0" max="999999">
59715971 </div>
59725972 </div>
59735973 <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a cooldown can't be activated N messages after being triggered." title="Entries with a cooldown can't be activated N messages after being triggered.">
@@ -5980,7 +5980,7 @@
59805980 </small>
59815981 </div>
59825982 <div class="range-block-range">
59835983 <input class="text_pole margin0" name="cooldown" type="number" data-i18n="[placeholder]No cooldown" placeholder="No cooldown" min="0" max="999999">
59845984 </div>
59855985 </div>
59865986 <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a delay can't be activated until there are N messages present in the chat." title="Entries with a delay can't be activated until there are N messages present in the chat.">
@@ -5993,7 +5993,7 @@
59935993 </small>
59945994 </div>
59955995 <div class="range-block-range">
59965996 <input class="text_pole margin0" name="delay" type="number" data-i18n="[placeholder]No delay" placeholder="No delay" min="0" max="999999">
59975997 </div>
59985998 </div>
59995999 </div>
public/locales/ar-sa.json+1 -1
@@ -879,7 +879,7 @@
879879 "popup-button-no": "لا",
880880 "popup-button-cancel": "يلغي",
881881 "popup-button-import": "يستورد",
882882 "Advanced DefininitionsDefinitions": "تعريفات متقدمة",
883883 "Prompt Overrides": "التجاوزات السريعة",
884884 "(For Chat Completion and Instruct Mode)": "(لاستكمال الدردشة ووضع التعليمات)",
885885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "أدخل {{original}} في أي مربع لتضمين التعليمات الافتراضية المعنية من إعدادات النظام.",
public/locales/de-de.json+1 -1
@@ -879,7 +879,7 @@
879879 "popup-button-no": "NEIN",
880880 "popup-button-cancel": "Stornieren",
881881 "popup-button-import": "Importieren",
882882 "Advanced DefininitionsDefinitions": "Erweiterte Definitionen",
883883 "Prompt Overrides": "Eingabeaufforderungsüberschreibungen",
884884 "(For Chat Completion and Instruct Mode)": "(Für Chat-Abschluss und Anweisungsmodus)",
885885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "Füge {{original}} in eines der Felder ein, um den jeweiligen Standardprompt aus den Systemeinstellungen einzuschließen.",
public/locales/es-es.json+109 -2
@@ -879,7 +879,7 @@
879879 "popup-button-no": "No",
880880 "popup-button-cancel": "Cancelar",
881881 "popup-button-import": "Importar",
882882 "Advanced DefininitionsDefinitions": "Definiciones avanzadas",
883883 "Prompt Overrides": "Anulaciones rápidas",
884884 "(For Chat Completion and Instruct Mode)": "(Para completar el chat y el modo de instrucción)",
885885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "Inserte {{original}} en cualquiera de las casillas para incluir las indicaciones predeterminadas respectivas de la configuración del sistema.",
@@ -1439,5 +1439,112 @@
14391439 "Still have questions?": "¿Todavía tienes preguntas?",
14401440 "Join the SillyTavern Discord": "Únete al Discord de SillyTavern",
14411441 "Post a GitHub issue": "Publicar un problema en GitHub",
14421442 "Contact the developers": "Contactar a los desarrolladores",
1443+ "Prome (Visual Novel Extension)": "Prome (Extensión de Modo Waifu/Novela Visual)",
1444+ "Brought to you by": "Presentado por",
1445+ "and Prometheus.": "y Prometheus.",
1446+ "Enable Prome": "Iniciar Prome",
1447+ "Toggles Prome, VN Mode and other Prome features.": "Activa Prome, el modo VN y otras funciones de Prome.",
1448+ "Features marked with a": "Las funciones marcadas con un",
1449+ "require Prome to be enabled.": "requieren que Prome esté iniciado.",
1450+ "Sheld Configuration": "Configuración de interfaz (Sheld)",
1451+ "Hide Sheld (Message Box)": "Ocultar Sheld (cuadro de mensajes)",
1452+ "Hide the message box (sheld) in the ST UI.": "Ocultar el cuadro de mensajes (sheld) en la interfaz de usuario de SillyTavern.",
1453+ "Enable Traditional VN Mode": "Modo VN tradicional*",
1454+ "Only Show Last Message in Chat (Requires Prome to be enabled).": "Mostrar solo el último mensaje en el chat (Requiere que Prome esté iniciado).",
1455+ "Letterbox Configuration*": "Configuración de la franja negra*",
1456+ "Letterbox Mode": "Modo de franja negra",
1457+ "Select the letterbox mode for the Prome VN UI.": "Seleccione el modo de franja negra para la interfaz de usuario VN de Prome.",
1458+ "Horizontal Letterbox": "Franja negra horizontal",
1459+ "Vertical Letterbox": "Franja negra vertical",
1460+ "Letterbox Color": "Color de la franja negra",
1461+ "Select the color of the letterbox.": "Seleccione el color de la franja negra.",
1462+ "Letterbox Size": "Tamaño de la franja negra",
1463+ "Set the size of the letterbox.": "Establezca el tamaño de la franja negra.",
1464+ "Sprite Configuration": "Configuración de sprites",
1465+ "Emulate Character Card as Sprite": "[BETA] Emular tarjeta de personaje como sprite",
1466+ "Emulates the character card of a character to be a sprite. (Requires Prome to be enabled).": "Emula la tarjeta de personaje de un personaje para que sea un sprite. (Requiere que Prome esté iniciado).",
1467+ "Enable Sprite Shake": "[BETA] Sprite Shake",
1468+ "Shakes the character sprite when the character is speaking (Only works if Streaming is enabled in Preset Settings).": "Agita el sprite del personaje cuando el personaje está hablando (solo funciona si la transmisión está habilitada en la configuración preestablecida).",
1469+ "Enable Focus Mode": "Modo de enfoque",
1470+ "Focuses the current speaking character in chat. (Requires Prome to be enabled).": "Enfoca al personaje que está hablando en el chat. (Requiere que Prome esté iniciado).",
1471+ "Darken Unfocused Character Sprites": "Oscurecer sprites de personajes",
1472+ "Darkens non-speaking (unfocused) characters. (Requires Prome to be enabled).": "Oscurece a los personajes que no hablan (no enfocados). (Requiere que Prome esté iniciado).",
1473+ "Auto-Hide Sprites": "Ocultar sprites automáticamente",
1474+ "Auto-hides characters from the screen that haven't been in the conversation for a while up to X characters. (Requires Prome to be enabled).": "Oculta automáticamente a los personajes de la pantalla que no han estado en la conversación durante un tiempo hasta X personajes. (Requiere que Prome esté iniciado).",
1475+ "Max Visible Sprites": "Máximo de personajes visibles",
1476+ "Set the maximum number of visible sprites that appears in the VN screen.": "Establezca el número máximo de sprites visibles que aparecen en la pantalla VN.",
1477+ "Sprite Shadow Configuration": "Configuración de sombra de sprites",
1478+ "Enable Sprite Shadow": "Sombra de sprite",
1479+ "Adds a shadow to the character sprite.": "Agrega una sombra al sprite del personaje.",
1480+ "Shadow X Offset": "Desplazamiento X de la sombra",
1481+ "Set the X offset of the character shadow.": "Establezca el desplazamiento X de la sombra del personaje.",
1482+ "Shadow Y Offset": "Desplazamiento Y de la sombra",
1483+ "Set the Y offset of the character shadow.": "Establezca el desplazamiento Y de la sombra del personaje.",
1484+ "Shadow Blur": "Desenfoque de sombra",
1485+ "Set the blur of the character shadow.": "Establezca el desenfoque de la sombra del personaje.",
1486+ "Focus Mode Settings": "Configuración del modo de enfoque",
1487+ "Focus Mode Animation": "Animación de modo de enfoque",
1488+ "Select the animation for focus mode.": "Seleccione la animación para el modo de enfoque.",
1489+ "Focus Mode Animation Speed": "Velocidad de animación del modo de enfoque",
1490+ "Set the speed of the focus animation.": "Establezca la velocidad de la animación de enfoque.",
1491+ "User Sprite Configuration": "[BETA] Configuración de sprites de usuario",
1492+ "Enable User Sprite": "Sprites de usuario",
1493+ "Enables the ability to use a user sprite for your persona.": "Habilita la capacidad de usar un sprite de usuario para tu persona.",
1494+ "Sprite set": "Conjunto de sprites",
1495+ "Type the name of the sprite set to use for your persona. (Place your sprites in the 'characters' folder in SillyTavern).": "Escriba el nombre del conjunto de sprites que desea utilizar para su persona. (Coloque sus sprites en la carpeta 'characters' en SillyTavern).",
1496+ "Note: Create a sprite folder in the ": "Nota: Cree una carpeta de sprites en el ",
1497+ " folder of your user directory (typically 'data/default-user'). Place your expressions there.": " carpeta de su directorio de usuario (normalmente 'data/default-user'). Coloque sus expresiones allí.",
1498+ "Tint Configuration": "Configuración de tono",
1499+ "Enable Chat Tint": "Tinte de chat",
1500+ "Tints the chat background and/or character sprites.": "Tinta el fondo del chat y/o los sprites de personajes.",
1501+ "Share World Tint With Characters": "Compartir tinte mundial con personajes*",
1502+ "Applies the world tint to character sprites (Requires Prome to be enabled. This will override your character tint settings).": "Aplica el tinte mundial a los sprites de personajes (Requiere que Prome esté iniciado. Esto anulará la configuración de tinte de su personaje).",
1503+ "Tint Presets": "Preajustes de tinte",
1504+ "Select the tint preset to use for the Prome VN UI.": "Seleccione el preajuste de tinte que desea utilizar para la interfaz de usuario VN de Prome.",
1505+ "World Tint Settings": "Configuración de tinte mundial",
1506+ "Tints the world background.": "Tinta el fondo mundial.",
1507+ "Enable World Tint": "Tinte mundial",
1508+ "Set the strength of the world blur.": "Establezca la fuerza del desenfoque mundial.",
1509+ "Brightness": "Brillo",
1510+ "Set the brightness of the world.": "Establezca el brillo del mundo.",
1511+ "Contrast": "Contraste",
1512+ "Set the contrast of the world.": "Establezca el contraste del mundial.",
1513+ "Grayscale": "Escala de grises",
1514+ "Makes the world black and white.": "Hace que el mundo sea en blanco y negro.",
1515+ "Hue": "Matiz",
1516+ "Set the hue of the world tint.": "Establezca el matiz del tinte mundial.",
1517+ "Invert": "Invertir",
1518+ "Inverts the world colors.": "Invierte los colores del mundo.",
1519+ "Saturate": "Saturar",
1520+ "Saturates the world colors.": "Satura los colores del mundo.",
1521+ "Makes the world warmer in color.": "Hace que el mundo sea más cálido en color.",
1522+ "Character Tint Settings": "Configuración de tinte de sprites*",
1523+ "Enable Character Tint (Requires Prome to be enabled)": "Tinte de sprites (Requiere que Prome esté iniciado)",
1524+ "Set the strength of the character blur.": "Establezca la fuerza del desenfoque de personajes.",
1525+ "Set the brightness of the character.": "Establezca el brillo de personaje.",
1526+ "Set the contrast of the character.": "Establezca el contraste de personajes.",
1527+ "Makes the character black and white.": "Hace que el personaje sea en blanco y negro.",
1528+ "Set the hue of the character.": "Establezca el matiz del tinte de personajes.",
1529+ "Inverts the character colors.": "Invierte los colores del personaje.",
1530+ "Saturates the character colors.": "Satura los colores del personaje.",
1531+ "Makes the character warmer in color.": "Hace que el personaje sea más cálido en color.",
1532+ "Keybinds": "Atajos de teclado",
1533+ "Commands": "Comandos",
1534+ "Prome Keybinds": "Combinaciones de teclas de Prome",
1535+ "Hide/Show SillyTavern's Sheld (Message Box)": "Ocultar/Mostrar el estante de SillyTavern (cuadro de mensaje)",
1536+ "Prome Commands": "Comandos de Prome",
1537+ "Show/Hide the letterbox (black bars) in the VN UI": "Mostrar/Ocultar la franja negra (barras negras) en la interfaz VN",
1538+ "Toggles focus mode on character sprites": "Alterna el modo de enfoque en los sprites de personajes",
1539+ "Sets the focus mode animation": "Establece la animación del modo de enfoque",
1540+ "Toggles the defocus tint on non-speaking character sprites": "Alterna el tinte de desenfoque en los sprites de personajes que no hablan",
1541+ "Toggles the shake animation when a character speaks on character sprites": "Alterna la animación de sacudida cuando un personaje habla en los sprites de personajes",
1542+ "Toggles sprite shadows on character sprites": "Alterna las sombras de los sprites de personajes",
1543+ "Toggles world/character tint on the VN UI": "Alterna el tinte mundial/de personajes en la interfaz VN",
1544+ "Toggles world tint on the VN UI": "Alterna el tinte mundial en la interfaz VN",
1545+ "Toggles character tint on the VN UI": "Alterna el tinte de personajes en la interfaz VN",
1546+ "Toggles sharing world tint with character sprites (This will override Character Tint)": "Alterna el tinte mundial compartido con los sprites de personajes (esto anulará el tinte de personajes)",
1547+ "Sets the expression of the user sprite": "Establece la expresión del sprite de usuario",
1548+ "Sets the user sprite set to use for the user sprite": "Establece el conjunto de sprites de usuario para usar en el sprite de usuario",
1549+ "Toggles the user sprite on the VN UI": "Alterna el sprite de usuario en la interfaz VN"
14431550}
public/locales/fr-fr.json+7 -6
@@ -823,11 +823,13 @@
823823 "popup-button-no": "Non",
824824 "popup-button-cancel": "Annuler",
825825 "popup-button-import": "Importer",
826826 "PromptAdvanced OverridesDefinitions": "Remplacements deDéfinitions promptavancées",
827- "(For Chat Completion and Instruct Mode)": "(Pour la complétion de chat et le mode instruction)",
827+ "Prompt Overrides": "Remplacements d'invite",
828- "Insert {{original}} into either box to include the respective default prompt from system settings.": "Insérez {{original}} dans l'un ou l'autre des champs pour inclure le prompt par défaut correspondante dans les paramètres système.",
828+ "(For Chat Completion and Instruct Mode)": "(Pour l'achèvement du chat et le mode instruction)",
829- "Main Prompt": "Prompt principal",
829+ "Insert {{original}} into either box to include the respective default prompt from system settings.": "Insérez {{original}} dans l'un ou l'autre des champs pour inclure l'instruction par défaut respective des paramètres système.",
830- "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Tout contenu ici remplacera le prompt principal par défaut utilisée pour ce personnage. (spéc v2 : system_prompt)",
830+ "Main Prompt": "Instruction principale",
831+ "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Tout contenu ici remplacera l'instruction principale par défaut utilisée pour ce personnage. (spécification v2 : système_prompt)",
832+ "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Tout contenu ici remplacera l'instruction de jailbreak par défaut utilisée pour ce personnage. (spécification v2 : post_history_instructions)",
831833 "Creator's Metadata (Not sent with the AI prompt)": "Métadonnées du créateur (Non envoyées avec l'instruction de l'IA)",
832834 "Creator's Metadata": "Métadonnées du créateur",
833835 "(Not sent with the AI Prompt)": "(Non envoyé avec le prompt IA)",
@@ -2041,7 +2043,6 @@
20412043 "Strategy": "Stratégie",
20422044 "Position": "Position",
20432045 "Trigger %": "Déclencheur %",
2044- "Advanced Definitions": "- Définitions\n Avancé",
20452046 "Only chunk on custom boundary": "Only chunk on custom boundary",
20462047 "Generate Caption": "Générer une légende",
20472048 "Use System Prompt": "Utiliser le prompt système:",
public/locales/is-is.json+1 -1
@@ -879,7 +879,7 @@
879879 "popup-button-no": "Nei",
880880 "popup-button-cancel": "Hætta við",
881881 "popup-button-import": "Flytja inn",
882882 "Advanced DefininitionsDefinitions": "Ítarleg skilgreiningar",
883883 "Prompt Overrides": "Hnekkja hvetjandi",
884884 "(For Chat Completion and Instruct Mode)": "(Til að ljúka spjalli og leiðbeiningarham)",
885885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "Settu inn {{original}} í hvora kassa til að innifela viðkomandi sjálfgefna framkallan frá kerfisstillingum.",
public/locales/it-it.json+1 -1
@@ -879,7 +879,7 @@
879879 "popup-button-no": "NO",
880880 "popup-button-cancel": "Annulla",
881881 "popup-button-import": "Importare",
882882 "Advanced DefininitionsDefinitions": "Definizioni avanzate",
883883 "Prompt Overrides": "Sostituzioni richieste",
884884 "(For Chat Completion and Instruct Mode)": "(Per il completamento della chat e la modalità istruzione)",
885885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "Inserisci {{originale}} in uno dei due riquadri per includere il prompt predefinito corrispondente dalle impostazioni di sistema.",
public/locales/ja-jp.json+1 -1
@@ -879,7 +879,7 @@
879879 "popup-button-no": "いいえ",
880880 "popup-button-cancel": "キャンセル",
881881 "popup-button-import": "インポート",
882882 "Advanced DefininitionsDefinitions": "高度な定義",
883883 "Prompt Overrides": "プロンプトのオーバーライド",
884884 "(For Chat Completion and Instruct Mode)": "(チャット補完と指示モード用)",
885885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "システム設定からの対応するデフォルトのプロンプトを含めるには、どちらかのボックスに{{original}}を挿入します。",
public/locales/ko-kr.json+1 -1
@@ -895,7 +895,7 @@
895895 "popup-button-no": "아니요",
896896 "popup-button-cancel": "취소",
897897 "popup-button-import": "불러오기",
898898 "Advanced DefininitionsDefinitions": "고급 정의",
899899 "Prompt Overrides": "프롬프트 무시",
900900 "(For Chat Completion and Instruct Mode)": "(채팅 완료 및 지시 모드의 경우)",
901901 "Insert {{original}} into either box to include the respective default prompt from system settings.": "{{original}}를 해당 상자에 넣어 시스템 설정의 기본 프롬프트를 포함합니다.",
public/locales/nl-nl.json+1 -1
@@ -879,7 +879,7 @@
879879 "popup-button-no": "Nee",
880880 "popup-button-cancel": "Annuleren",
881881 "popup-button-import": "Importeren",
882882 "Advanced DefininitionsDefinitions": "Geavanceerde definities",
883883 "Prompt Overrides": "Prompt-overschrijvingen",
884884 "(For Chat Completion and Instruct Mode)": "(Voor voltooiing van chat en instructiemodus)",
885885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "Voeg {{original}} in in elk vak in om de respectievelijke standaardprompt vanuit systeeminstellingen op te nemen.",
public/locales/pt-pt.json+1 -1
@@ -879,7 +879,7 @@
879879 "popup-button-no": "Não",
880880 "popup-button-cancel": "Cancelar",
881881 "popup-button-import": "Importar",
882882 "Advanced DefininitionsDefinitions": "Definições Avançadas",
883883 "Prompt Overrides": "Substituições de prompt",
884884 "(For Chat Completion and Instruct Mode)": "(Para conclusão de bate-papo e modo de instrução)",
885885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "Insira {{original}} em qualquer caixa para incluir o prompt padrão respectivo das configurações do sistema.",
public/locales/ru-ru.json+125 -16
@@ -265,7 +265,7 @@
265265 "Current Members": "Текущие участники",
266266 "Delete": "Удалить",
267267 "Cancel": "Отменить",
268268 "Advanced DefininitionsDefinitions": "Расширенное описание",
269269 "Personality summary": "Резюме по личности",
270270 "Scenario": "Сценарий",
271271 "Talkativeness": "Разговорчивость",
@@ -294,7 +294,7 @@
294294 "Avoid sending sensitive information to the Horde.": "Избегайте отправки личной информации Horde",
295295 "Review the Privacy statement": "Ознакомиться с заявлением о конфиденциальности",
296296 "Trusted workers only": "Только доверенные рабочие машины",
297297 "For privacy reasons, your API key will be hidden after you reload the page.": "ПоИз причинамсоображений безопасности ваш API-ключ будет скрыт после перезагрузки страницы.",
298298 "-- Horde models not loaded --": "--Модель Horde не загружена--",
299299 "Example: http://127.0.0.1:5000/api ": "Пример: http://127.0.0.1:5000/api",
300300 "No connection...": "Нет соединения...",
@@ -331,7 +331,6 @@
331331 "UID ↘": "UID ↘",
332332 "Trigger% ↗": "Триггер% ↗",
333333 "Trigger% ↘": "Триггер% ↘",
334- "Order:": "Порядок:",
335334 "Depth:": "Глубина:",
336335 "Character Lore First": "Сначала лор персонажа",
337336 "Global Lore First": "Сначала глобальный лор",
@@ -347,7 +346,7 @@
347346 "After Char Defs": "↓Перс.",
348347 "Before AN": "↑АЗ",
349348 "After AN": "↓АЗ",
350349 "Order": "ПорядокОчерёдность:",
351350 "Update a theme file": "Обновить файл темы",
352351 "Save as a new theme": "Сохранить как новую тему",
353352 "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.",
@@ -497,7 +496,7 @@
497496 "What this keyword should mean to the AI, sent verbatim": "Что это ключевое слово должно означать для ИИ, отправляется дословно",
498497 "Filter to Character(s)": "Фильтр по персонажу(ам)",
499498 "Character Exclusion": "Исключить персонажей",
500499 "Inclusion Group": "ВключитьГруппа персонажейзаписей",
501500 "Only one entry with the same label will be activated": "Будет активна только одна запись с одинаковой меткой",
502501 "-- Characters not found --": "-- Персонажей не найдено --",
503502 "(This will be the first message from the character that starts every chat)": "(Это будет первое сообщение от персонажа, когда вы начинаете новый чат)",
@@ -541,7 +540,7 @@
541540 "NOT ANY": "НЕ ЛЮБОЙ",
542541 "Optional Filter": "Дополнительный фильтр",
543542 "New Entry": "Новая запись",
544543 "Fill empty Memo/Titles with Keywords": "ЗаполнитеЗаполнить пустые Заметки/Названияназвания ключевыми словами",
545544 "AI Response Formatting": "Формат ответа ИИ",
546545 "Change Background Image": "Изменить фон",
547546 "Extensions": "Расширения",
@@ -628,7 +627,7 @@
628627 "UI Theme": "Тема UI",
629628 "This message is invisible for the AI": "Это сообщение невидимо для ИИ",
630629 "Sampler Priority": "Приоритет сэмплеров",
631630 "Ooba only. Determines the order of samplers.": "Только Oobaoobabooga. Определяет порядок сэмплеров.",
632631 "Load default order": "Загрузить стандартный порядок",
633632 "Max Tokens Second": "Макс. кол-во токенов в секунду",
634633 "CFG": "CFG",
@@ -1132,7 +1131,7 @@
11321131 "Custom API Key": "Ключ от кастомного API",
11331132 "(Optional)": "(необязательно)",
11341133 "Enter a Model ID": "Введите идентификатор модели",
11351134 "Example: gpt-3.5-turbo4o": "Пример: gpt-3.5-turbo4o",
11361135 "Available Models": "Доступные модели",
11371136 "Prompt Post-Processing": "Постобработка промпта",
11381137 "Applies additional processing to the prompt before sending it to the API.": "Позволяет обработать промпт перед отправкой в API.",
@@ -1342,7 +1341,7 @@
13421341 "Chat Lorebook": "Chat Lorebook for",
13431342 "chat_world_template_txt": "A selected World Info will be bound to this chat. When generating an AI reply,\n it will be combined with the entries from global and character lorebooks.",
13441343 "Use tag as folder": "Tag as folder",
13451344 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "Статус записи:\n 🔵 Постоянная\n 🟢 Обычная\n 🔗 Векторизованная\n ❌ Отключена",
13461345 "WI_Entry_Status_Constant": "Постоянная",
13471346 "WI_Entry_Status_Normal": "Обычная",
13481347 "WI_Entry_Status_Vectorized": "Векторизованная",
@@ -1366,13 +1365,7 @@
13661365 "Can be used to automatically activate Quick Replies": "Can be used to automatically activate Quick Replies",
13671366 "Automation ID": "Automation ID",
13681367 "( None )": "( None )",
1369- "Delay until recursion (this entry can only be activated on recursive checking)": "Delay until recursion (this entry can only be activated on recursive checking)",
1370- "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.\rSupports multiple comma-separated groups.\r\rDocumentation: World Info - Inclusion Group",
1371- "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Prioritize this entry: When checked, this entry is prioritized out of all selections.\rIf multiple are prioritized, the one with the highest 'Order' is chosen.\r",
1372- "A relative likelihood of entry activation within the group": "A relative likelihood of entry activation within the group",
1373- "Group Weight": "Group Weight",
13741368 "Add Memo": "Add Memo",
1375- "close": "close",
13761369 "reset": "reset",
13771370 "save": "save",
13781371 "Open checkpoint chat": "Открыть чат из чекпоинта",
@@ -2035,5 +2028,121 @@
20352028 "tags_sorting_desc": "Автоматически сортировать теги по алфавиту после создания или переименования одного из них.\nПри выключении новые теги будут просто добавляться в конец.\n\nЕсли вручную перетащить один из тегов на другое место, автосортировка отключится.",
20362029 "Imported tags:": "Импортируемые теги:",
20372030 "Importing Tags": "Импорт тегов",
20382031 "Couldn't import tags:": "Не удалось импортировать теги:",
2032+ "Allow fallback models": "Разрешить fallback-модели",
2033+ "Allow fallback providers": "Разрешить fallback-провайдеров",
2034+ "To use instruct formatting, switch to OpenRouter under Text Completion API.": "Переключитесь на OpenRouter в Text Completion API, чтобы использовать форматирование Instruct-режима.",
2035+ "Select providers. No selection = all providers.": "Выберите провайдера. Нет выбранного = выбраны все.",
2036+ "Model Providers": "Провайдеры моделей",
2037+ "Select a model": "Выберите модель",
2038+ "Search models...": "Искать по моделям...",
2039+ "[Currently loaded]": "[Загруженная сейчас]",
2040+ "Search providers...": "Искать по провайдерам...",
2041+ "Automatically chooses an alternative provider if chosen providers can't serve your request.": "Автоматически переключаться на другого провайдера, если текущий не может обслужить запрос.",
2042+ "Example: 127.0.0.1:8000": "Пример: 127.0.0.1:8000",
2043+ "Edit a connection profile": "Редактировать профиль соединения",
2044+ "System Prompt Name": "Название системного промпта",
2045+ "Use System Prompt": "Использовать системный промпт",
2046+ "Hint:": "Подсказка:",
2047+ "Click on the setting name to omit it from the profile.": "Нажмите на название настройки, чтобы исключить её из профиля",
2048+ "Included settings:": "Сохранённые параметры:",
2049+ "Server URL": "Адрес сервера",
2050+ "NanoGPT API Key": "Ключ от API NanoGPT",
2051+ "NanoGPT Model": "Модель NanoGPT",
2052+ "Use extension settings": "Использовать настройки из расширения",
2053+ "DeepSeek API Key": "Ключ от API DeepSeek",
2054+ "DeepSeek Model": "Модель DeepSeek",
2055+ "prompt_post_processing_merge": "Объединять идущие подряд сообщения с одной ролью",
2056+ "prompt_post_processing_semi": "Semi-strict (чередовать роли)",
2057+ "prompt_post_processing_strict": "Strict (чередовать роли, сначала пользователь)",
2058+ "Select Horde models": "Выбрать модель из Horde",
2059+ "Model ID (optional)": "Идентификатор модели (необязательно)",
2060+ "Derive context size from backend": "Использовать бэкенд для определения размера контекста",
2061+ "Rename current preset": "Переименовать пресет",
2062+ "No Worlds active. Click here to select.": "Нет активных миров. Нажмите, чтобы выбрать.",
2063+ "Title/Memo": "Название",
2064+ "Strategy": "Статус",
2065+ "Position": "Позиция",
2066+ "Trigger %": "% срабатывания",
2067+ "Use global": "Глоб. настройка",
2068+ "Whole Words": "Целые слова",
2069+ "Non-recursable (will not be activated by another)": "Не рекурсивная (не активируется другими)",
2070+ "Delay until recursion (can only be activated on recursive checking)": "Рекурсивная (активируется только рекурсией)",
2071+ "Toggle entry's active state.": "Вкл/выкл запись.",
2072+ "Prioritize": "Важная",
2073+ "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Важная запись получает приоритет среди всех выбранных. Если важных записей несколько, выбирается та, у которой выше \"Очерёдность\".",
2074+ "Group Weight": "Вес в группе",
2075+ "A relative likelihood of entry activation within the group": "Относительная вероятность активации записи в рамках группы",
2076+ "Sticky": "Липучка",
2077+ "Sticky entries will stay active for N messages after being triggered.": "Запись-\"липучка\" останется активной в течение N сообщений после срабатывания.",
2078+ "Cooldown": "Кулдаун",
2079+ "Entries with a cooldown can't be activated N messages after being triggered.": "Запись с заданным кулдауном не активируется следующие N сообщений после срабатывания.",
2080+ "Delay": "Задержка",
2081+ "Entries with a delay can't be activated until there are N messages present in the chat.": "Запись с заданной задержкой может активироваться только после того, как в чате наберётся N сообщений.",
2082+ "Non-sticky": "Нет",
2083+ "No cooldown": "Нет",
2084+ "No delay": "Нет",
2085+ "Filter to Characters or Tags": "Фильтровать по персонажам или тегам",
2086+ "Switch to plaintext mode": "Вкл/выкл режим чистого текста",
2087+ "Exclude": "Режим исключения",
2088+ "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "Инвертировать логику: для выбранных в фильтре персонажей/тегов данная запись активна НЕ БУДЕТ",
2089+ "Apply current sorting as Order": "Настроить Очерёдность в соответствии с текущей сортировкой",
2090+ "Create a new World Info": "Создать новый мир",
2091+ "Enter a name for the new file:": "Название нового файла:",
2092+ "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Если сразу несколько записей из одной группы окажутся активированными, по факту сработает только одна. Одна запись может входить в несколько групп, отделяются запятыми. Раздел в документации: World Info - Inclusion Group",
2093+ "Valid World Info file name is required": "Требуется корректное имя для файла мира",
2094+ "World Info file has an invalid format": "Файл мира имеет неизвестный формат",
2095+ "World Info file has no entries": "В файле нет ни одной записи",
2096+ "Character not found.": "Персонаж не найден",
2097+ "Open a chat to get a name of the chat-bound lorebook": "Чтобы получить название привязанного к чату лорбука, требуется открыть чат.",
2098+ "File is not valid: ${0}": "Файл повреждён или имеет неизвестный формат: ${0}",
2099+ "The world with ${0} is invalid or corrupted.": "Мир ${0} повреждён или имеет неизвестный формат.",
2100+ "Deactivated all worlds": "Все миры отключены",
2101+ "No world found named: ${0}": "Не найдено мира с название ${0}",
2102+ "Activated world: ${0}": "Мир ${0} включён",
2103+ "Deactivated world: ${0}": "Мир ${0} отключён",
2104+ "World was not active: ${0}": "Мир ${0} не включён",
2105+ "The world '${0}' has been imported and linked to the character successfully.": "Мир ${0} успешно импортирован и привязан к персонажу.",
2106+ "World/Lorebook imported": "Мир/лорбук импортирован",
2107+ "Are you sure you want to import '${0}'?": "Вы точно хотите импортировать '${0}'?",
2108+ "It will overwrite the World/Lorebook with the same name.": "Существующий мир с таким же названием будет перезаписан.",
2109+ "Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.": "Автоматически \"продолжать\" ответ, если он оказался короче, чем целевая длина (в токенах).",
2110+ "None (not injected)": "Никуда",
2111+ "ext_sum_injection_position_none": "Пересказ не будет вставляться в промпт. Однако его по-прежнему можно будет вставить с помощью макроса {{summary}}",
2112+ "ext_sum_include_wi_scan": "Учитывать при сканировании лорбуком",
2113+ "ext_sum_include_wi_scan_desc": "Учитывать актуальный пересказ при сканировании промпта лорбуком.",
2114+ "ext_sum_force_tip": "Отправить запрос на создание пересказа прямо сейчас.",
2115+ "ext_sum_restore_tip": "Откатиться к предыдущему пересказу; используйте несколько раз, чтобы очистить историю пересказов для чата",
2116+ "Built-in Extensions:": "Комплектные расширения:",
2117+ "Installed Extensions:": "Установленные расширения:",
2118+ "Loading third-party extensions... Please wait...": "Загрузка сторонних расширений... Пожалуйста, подождите...",
2119+ "The page will be reloaded shortly...": "Страница будет перезагружена...",
2120+ "Extensions state changed": "Изменено состояние расширения",
2121+ "Error loading extensions. See browser console for details.": "Не удалось загрузить расширения. Подробности см. в консоли браузера.",
2122+ "You don't have permission to update global extensions.": "Отсутствуют права на обновление глобальных расширений.",
2123+ "Extension update failed": "Не удалось обновить расширение",
2124+ "Extension ${0} updated to ${1}": "Расширение ${0} обновлено до ${1}",
2125+ "Reload the page to apply updates": "Чтобы изменения вступили в силу, обновите страницу",
2126+ "You don't have permission to delete global extensions.": "Отсутствуют права на удаление глобальных расширений.",
2127+ "Are you sure you want to delete ${0}?": "Вы точно хотите удалить ${0}?",
2128+ "You don't have permission to move extensions.": "Отсутствуют права на перемещение расширений.",
2129+ "Are you sure you want to move ${0} to your local extensions? This will make it available only for you.": "Вы точно хотите сделать ${0} локальным расширением? После этого оно будет доступно только вам.",
2130+ "Are you sure you want to move ${0} to the global extensions? This will make it available for all users.": "Вы точно хотите сделать ${0} глобальным расширением? После этого оно будет доступно всем пользователям.",
2131+ "Extension ${0} moved.": "Расширение ${0} перемещено.",
2132+ "Extension ${0} deleted": "Расширение ${0} удалено.",
2133+ "Please wait...": "Пожалуйста, подождите...",
2134+ "Installing extension": "Идёт установка расширения",
2135+ "Extension installation failed": "Не удалось установить расширение",
2136+ "Extension '${0}' by ${1} (version ${2}) has been installed successfully!": "Расширение ${0} от автора ${1} (версия ${2}) успешно установлено!",
2137+ "Extension installation successful": "Расширение установлено",
2138+ "Extension updates available": "Доступных обновлений расширений",
2139+ "Auto-updating extensions. This may take several minutes.": "Запущено автоматическое обновление расширений. Это может занять несколько минут.",
2140+ "Install just for me": "Установить только мне",
2141+ "Install": "Установить",
2142+ "Install for all users": "Установить для всех пользователей",
2143+ "Modules provided by your Extras API:": "Модули из Extras API:",
2144+ "Not connected to the API!": "Нет соединения с API!",
2145+ "ext_type_system": "Это комплектное расширение. Его нельзя удалить, а обновляется оно вместе со всей системой.",
2146+ "Update all": "Обновить все",
2147+ "Close": "Закрыть"
20392148}
public/locales/uk-ua.json+1 -1
@@ -879,7 +879,7 @@
879879 "popup-button-no": "Немає",
880880 "popup-button-cancel": "Скасувати",
881881 "popup-button-import": "Імпорт",
882882 "Advanced DefininitionsDefinitions": "Розширені визначення",
883883 "Prompt Overrides": "Перевизначення підказок",
884884 "(For Chat Completion and Instruct Mode)": "(Для завершення чату та режиму інструктажу)",
885885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "Вставте {{original}} в будь-яке поле, щоб включити відповідний запит з налаштувань системи.",
public/locales/vi-vn.json+1 -1
@@ -879,7 +879,7 @@
879879 "popup-button-no": "KHÔNG",
880880 "popup-button-cancel": "Hủy",
881881 "popup-button-import": "Nhập",
882882 "Advanced DefininitionsDefinitions": "Các Định nghĩa Nâng cao",
883883 "Prompt Overrides": "Ghi đè Prompt",
884884 "(For Chat Completion and Instruct Mode)": "(Đối với chế độ hoàn thành trò chuyện và hướng dẫn)",
885885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "Chèn {{original}} vào bất kỳ hộp nào để bao gồm Prompt mặc định tương ứng từ cài đặt hệ thống.",
public/locales/zh-cn.json+103 -61
@@ -78,7 +78,7 @@
7878 "Allow": "Allow",
7979 "Forbid": "Forbid",
8080 "Enable OpenAI completion streaming": "启用OpenAI文本补全流式传输",
8181 "Display the response bit by bit as it is generated.": "随着回复的生成,逐位显示结果逐词逐句地显示结果。",
8282 "When this is off, responses will be displayed all at once when they are complete.": "当此选项关闭时,回复将在完成后一次性显示。",
8383 "Frequency Penalty": "频率惩罚",
8484 "Presence Penalty": "存在惩罚",
@@ -185,13 +185,13 @@
185185 "Mirostat Eta": "Mirostat η",
186186 "Learning rate of Mirostat": "Mirostat 的学习率。",
187187 "Beam search": "束搜索",
188188 "A greedy, brute-force algorithm used in LLM sampling to find the most likely sequence of words or tokens. It expands multiple candidate sequences at once, maintaining a fixed number (beam width) of top sequences at each step.": "A greedy, brute-force algorithm used in LLM sampling to find the most likely sequence of words or tokens. It expands multiple candidate sequences at once, maintaining a fixed number (beam width) of top sequences at each step.一种在LLM采样中使用的贪婪暴力算法,用于找到最可能的单词或标记序列。它一次扩展多个候选序列,在每一步保留固定数量(光束宽度)的最佳序列。",
189189 "# of Beams": "# of Beams光束数量",
190190 "The number of sequences generated at each step with Beam Search.": "The number of sequences generated at each step with Beam Search.",
191191 "Length Penalty": "长度惩罚",
192192 "Penalize sequences based on their length.": "Penalize sequences based on their length.",
193193 "Early Stopping": "提前停止",
194194 "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.": "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.控制光束搜索的停止条件。勾选时,当生成到达‘光束数量’的序列时停止。如果未勾选,则采用启发式方法,当几乎不可能找到更好的候选项时停止生成。",
195195 "Contrastive search": "对比搜索",
196196 "Contrastive_search_txt": "通过利用大多数 LLM 表示空间的各向同性以鼓励多样性同时保持一致性的采样器。详见 Su 等人在 2022 年发表的论文 《A Contrastive Framework for Neural Text Generation》。",
197197 "Penalty Alpha": "惩罚系数 α",
@@ -208,7 +208,7 @@
208208 "Speculative Ngram": "推测性 Ngram",
209209 "Use a different speculative decoding method without a draft model": "使用不同的推测解码方法(不采用草稿模型)。最好使用草稿模型。推测性 Ngram 的效果不太好。",
210210 "Spaces Between Special Tokens": "特殊词符之间的空格",
211- "Seed_desc": "A random seed to use for deterministic and reproducable outputs. Set to -1 to use a random seed.",
211+ "Seed_desc": "一个用于生成确定性和可复现的输出的随机种子。设置为 -1 时会使用随机种子。",
212212 "LLaMA / Mistral / Yi models only": "LLaMA / Mistral / Yi模型专用。首先确保您选择了适当的词符化器。\n这项设置决定了你不想在结果中看到的字符串。\n每行一个字符串。可以是文本或者[词符id]。\n许多词符以空格开头。如果不确定,请使用词符计数器。",
213213 "Example: some text [42, 69, 1337]": "例如:\n一些文本\n[42, 69, 1337]",
214214 "CFG": "CFG",
@@ -227,8 +227,8 @@
227227 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "仅限 llama.cpp。确定采样器的顺序。如果 Mirostat 模式不为 0,则忽略采样器顺序。",
228228 "Sampler Priority": "采样器优先级",
229229 "Ooba only. Determines the order of samplers.": "确定采样器的顺序(仅适用于Ooba)",
230230 "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "Aphrodite only. Determines the order of samplers.仅适用于 Aphrodite,用于确定采样器的顺序。偏移(Skew is always applied)始终在 post-softmax, so it's not included here.后应用,因此不包含在这里。",
231231 "Aphrodite only. Determines the order of samplers.": "Aphrodite only. Determines the order of仅适用于 samplers.Aphrodite。用于确定采样器的顺序。",
232232 "Character Names Behavior": "角色名称行为",
233233 "Helps the model to associate messages with characters.": "有助于模型将消息与角色关联起来。",
234234 "None": "无",
@@ -266,13 +266,15 @@
266266 "Use system prompt": "使用系统提示词",
267267 "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过",
268268 "Merges_all_system_messages_desc_2": "字段发送。",
269+ "Show model thoughts": "展示思维链",
270+ "Display the model's internal thoughts in the response.": "展示模型在回复时的内部思维链。",
269271 "Assistant Prefill": "AI预填",
270272 "Expand the editor": "展开编辑器",
271273 "Start Claude's answer with...": "以如下内容开始Claude的回答...",
272274 "Assistant Impersonation Prefill": "AI帮答预填",
273275 "Use system prompt (Claude 2.1+ only)": "使用系统提示词(仅适用于Claude 2.1+)",
274276 "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "为支持的模型发送系统提示词。如果禁用,则用户消息将添加到提示词的开头。",
275277 "Confirm token parsing with": "Confirm token parsing with确认使用以下工具进行词符解析",
276278 "Tokenizer": "词符化器",
277279 "New preset": "新预设",
278280 "Delete preset": "删除预设",
@@ -316,9 +318,9 @@
316318 "Get your NovelAI API Key": "获取您的 NovelAI API 密钥",
317319 "Enter it in the box below": "在下面的框中输入",
318320 "Novel AI Model": "Novel AI 模型",
319321 "No connection...": "没有连接无连接...",
320322 "API Type": "API 类型",
321323 "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "Generic通用(兼容 (OpenAI-compatible) [LM Studio, LiteLLM, etc.]",
322324 "TogetherAI API Key": "TogetherAI API 密钥",
323325 "TogetherAI Model": "TogetherAI 模型",
324326 "-- Connect to the API --": "-- 连接到API --",
@@ -350,7 +352,7 @@
350352 "All": "All",
351353 "class": "All Classes",
352354 "Toggle grid view": "切换网格视图",
353355 "No model description": "[No description无描述]",
354356 "vllm-project/vllm": "vllm-project/vllm(OpenAI API 包装器模式)",
355357 "vLLM API key": "vLLM API 密钥",
356358 "Example: 127.0.0.1:8000": "示例:http://127.0.0.1:8000",
@@ -399,12 +401,12 @@
399401 "View API Usage Metrics": "查看API使用情况",
400402 "Follow": "按照",
401403 "these directions": "这些步骤",
402404 "to get your OpenAI API key.": "获取您的OpenAI获取您的 API密钥OpenAI API 密钥。",
403405 "Use Proxy password field instead. This input will be ignored.": "请使用“代理密码”字段。此输入将被忽略。",
404406 "OpenAI Model": "OpenAI 模型",
405407 "Bypass API status check": "绕过API状态检查",
406408 "Show External models (provided by API)": "显示外部模型(由API提供)",
407409 "Claude API Key": "Claude API Key密钥",
408410 "Get your key from": "从以下位置获取您的密钥",
409411 "Anthropic's developer console": "Anthropic 开发者控制台",
410412 "Claude Model": "Claude 模型",
@@ -430,23 +432,28 @@
430432 "Groq Model": "Groq 模型",
431433 "NanoGPT API Key": "NanoGPT API Key",
432434 "NanoGPT Model": "NanoGPT Model",
435+ "DeepSeek API Key": "DeepSeek API 密钥",
436+ "DeepSeek Model": "DeepSeek 模型",
433437 "Perplexity API Key": "Perplexity API 密钥",
434438 "Perplexity Model": "Perplexity 模型",
435439 "Cohere API Key": "Cohere API 密钥",
436440 "Cohere Model": "Cohere 模型",
437441 "Block Entropy API Key": "Block Entropy API Key密钥",
438442 "Select a Model": "Select a Model选择一个模型",
439443 "Custom Endpoint (Base URL)": "自定义端点(基本基础 URL)",
440444 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",
441445 "at the end of the URL!": "到 URL 的末尾!",
442446 "Custom API Key": "自定义 API 密钥",
443447 "(Optional)": "(可选)",
444448 "Enter a Model ID": "输入模型名",
445449 "Example: gpt-3.5-turbo4o": "例如:gpt-3.5-turbo4o",
446450 "Available Models": "可用模型",
447451 "Prompt Post-Processing": "提示词后处理",
448452 "Applies additional processing to the prompt before sending it to the API.": "在将提示词发送到 API 之前对其进行额外处理。",
449453 "prompt_post_processing_none": "未选择",
454+ "prompt_post_processing_merge": "合并相同角色连续的发言",
455+ "prompt_post_processing_semi": "半严格(强制对话角色交替)",
456+ "prompt_post_processing_strict": "严格(强制对话角色交替、用户最先)",
450457 "01.AI API Key": "01.AI API密钥",
451458 "01.AI Model": "01.AI 模型",
452459 "Additional Parameters": "附加参数",
@@ -503,25 +510,25 @@
503510 "Never": "永不",
504511 "Groups and Past Personas": "Groups and Past Personas",
505512 "Always": "永远",
506513 "Instruct Sequences": "Instruct Sequences指令序列",
507514 "User Message Sequences": "User Message Sequences用户消息序列",
508515 "Inserted before a User message and as a last prompt line when impersonating.": "插入到用户消息之前并作为模拟时的最后一行提示词。",
509516 "User Prefix": "用户消息前缀",
510517 "Inserted after a User message.": "插入到用户消息之后。",
511518 "User Suffix": "用户消息后缀",
512519 "Assistant Message Sequences": "Assistant Message Sequences助手消息序列",
513520 "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "插入到助手消息之前并作为生成 AI 回复时的最后一行提示词。",
514521 "Assistant Prefix": "助手消息前缀",
515522 "Inserted after an Assistant message.": "插入于助手消息之后。",
516523 "Assistant Suffix": "助手消息后缀",
517524 "System Message Sequences": "System Message Sequences系统消息序列",
518525 "Inserted before a System (added by slash commands or extensions) message.": "插入到系统(由快捷命令或扩展添加)消息之前。",
519526 "System Prefix": "System Message Prefix系统消息前缀",
520527 "Inserted after a System message.": "插入到系统消息之后。",
521528 "System Suffix": "System Message Suffix系统消息后缀",
522529 "If enabled, System Sequences will be the same as User Sequences.": "如果启用,系统序列将与用户序列相同。",
523530 "System same as User": "系统与用户相同",
524531 "System Prompt Sequences": "System Prompt Sequences系统提示词序列",
525532 "Inserted before a System prompt.": "插入到系统提示词之前。",
526533 "System Prompt Prefix": "系统提示词前缀",
527534 "Inserted after a System prompt.": "在系统提示词后插入。",
@@ -556,7 +563,7 @@
556563 "Token Padding": "词符填充",
557564 "Miscellaneous": "杂项",
558565 "Non-markdown strings": "非 Markdown 字符串",
559566 "comma delimited,no spaces between": "comma delimited,no spaces between以逗号分隔,无需空格",
560567 "Start Reply With": "以...开始回复",
561568 "Show reply prefix in chat": "在聊天中显示回复前缀",
562569 "World Info": "世界信息",
@@ -688,8 +695,8 @@
688695 "Show Message Token Count": "显示消息词符数",
689696 "Single-row message input area. Mobile only, no effect on PC": "将输入框限制为一行。仅适用于移动设备,对PC无影响",
690697 "Compact Input Area (Mobile)": "紧凑输入区域(移动端)",
691698 "Display swipe numbers for all messages, not just the last.": "Display swipe numbers for all messages, not just the last.显示所有信息的滑动编号,而非仅限最后一条。",
692699 "Swipe # for All Messages": "Swipe给所有信息分配滑动编号 # for All Messages",
693700 "In the Character Management panel, show quick selection buttons for favorited characters": "在角色管理面板中,显示快速选择按钮以选择收藏的角色",
694701 "Characters Hotswap": "角色卡热切换",
695702 "Enable magnification for zoomed avatar display.": "启用放大功能以放大头像显示。",
@@ -894,7 +901,7 @@
894901 "Favorite characters to add them to HotSwaps": "收藏角色以将它们添加到快速热切换区",
895902 "Token counts may be inaccurate and provided just for reference.": "词符计数可能不准确,仅供参考。",
896903 "Total tokens": "总词符数",
897904 "Calculating...": "正在计算...",
898905 "Tokens": "词符数",
899906 "Permanent tokens": "永久词符",
900907 "Permanent": "恒定的",
@@ -936,10 +943,10 @@
936943 "Chat Name (Optional)": "聊天名称(可选)",
937944 "Chat Lore": "聊天知识",
938945 "Click to select a new avatar for this group": "单击选择该群聊的新头像",
939946 "Group reply strategy": "群聊回复策略群聊发言顺序",
940947 "Manual": "手动",
941948 "Natural order": "自然顺序",
942949 "List order": "上下顺序从上到下",
943950 "Group generation handling mode": "群组生成处理模式",
944951 "Swap character cards": "交换角色卡",
945952 "Join character cards (exclude muted)": "加入角色卡(不包括被禁言的)",
@@ -990,7 +997,7 @@
990997 "popup-button-import": "导入",
991998 "popup-button-crop": "裁剪",
992999 "Close popup": "关闭弹出窗口",
9931000 "Advanced DefininitionsDefinitions": "高级定义",
9941001 "Prompt Overrides": "提示词覆盖",
9951002 "(For Chat Completion and Instruct Mode)": "(用于聊天补全和指导模式)",
9961003 "Insert {{original}} into either box to include the respective default prompt from system settings.": "将{{original}}插入到任一框中,以包含系统设置中的相应默认提示词。",
@@ -1023,7 +1030,7 @@
10231030 "Chatty": "高",
10241031 "Examples of dialogue": "对话示例",
10251032 "Important to set the character's writing style.": "设置角色的写作风格,很重要!",
10261033 "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天对话的示例,每个示例都另起一行以<START>开头。)",
10271034 "Save": "保存",
10281035 "Chat History": "聊天记录",
10291036 "Import Chat": "导入聊天",
@@ -1107,12 +1114,15 @@
11071114 "A relative likelihood of entry activation within the group": "组内进入激活的相对可能性",
11081115 "Group Weight": "组权重",
11091116 "Sticky entries will stay active for N messages after being triggered.": "粘性条目在被触发后将保持活跃状态​​ N 条消息。",
11101117 "Sticky": "粘性黏性",
1118+ "Non-sticky": "无黏性",
11111119 "Entries with a cooldown can't be activated N messages after being triggered.": "具有冷却时间的条目在触发后 N 条消息内无法被激活。",
11121120 "Cooldown": "冷却",
1121+ "No cooldown": "无冷却",
11131122 "Entries with a delay can't be activated until there are N messages present in the chat.": "直到聊天中出现 N 条消息时,延迟的条目才能被激活。",
11141123 "Delay": "延迟",
11151124 "Filter to Characters orNo Tagsdelay": "应用到角色或标签无延迟",
1125+ "Filter to Characters or Tags": "绑定到角色或标签",
11161126 "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "切换角色/标签筛选方式,将列出的角色和标签排除在匹配范围之外",
11171127 "Exclude": "排除",
11181128 "-- Characters not found --": "-- 未找到角色 --",
@@ -1132,8 +1142,8 @@
11321142 "prompt_manager_relative": "相对",
11331143 "prompt_manager_in_chat": "聊天中",
11341144 "prompt_manager_depth": "深度",
11351145 "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。0 = 在最后一条消息之后”为在最后一条消息之后1 = 在最后一条消息之前”为在最后一条消息之前,等等。",
11361146 "The content of this prompt is pulled from elsewhere and cannot be edited here.": "The content of this prompt is pulled from elsewhere and cannot be edited here.此提示词的内容是从其他地方提取的,无法在此处进行编辑。",
11371147 "Prompt": "提示词",
11381148 "The prompt to be sent.": "要发送的提示词。",
11391149 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使选择覆盖,此提示词也不能被角色卡覆盖。",
@@ -1194,7 +1204,7 @@
11941204 "alternate_greetings_hint_1": "点击",
11951205 "alternate_greetings_hint_2": "按钮即可开始!",
11961206 "Alternate Greeting #": "额外问候语 #",
11971207 "(This will be the first message from the character that starts every chat)": "(这是每次聊天开始时角色的第一条消息)",
11981208 "View contents": "查看内容",
11991209 "Remove the file": "删除文件",
12001210 "Author's Note": "作者注释",
@@ -1207,7 +1217,7 @@
12071217 "Insertion Frequency": "插入频率",
12081218 "(0 = Disable, 1 = Always)": "(“0”为禁用,“1”为始终)",
12091219 "User inputs until next insertion:": "用户输入直到下一次插入:",
12101220 "Character Author's Note (Private)": "人物作者注(私有私密)",
12111221 "Won't be shared with the character card on export.": "导出时不会与角色卡共享。",
12121222 "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "会自动添加为该角色的作者注解,在群聊中使用,但群聊开启时无法修改。",
12131223 "Use character author's note": "使用角色作者的注释",
@@ -1234,9 +1244,9 @@
12341244 "Insertion Depth:": "插入深度:",
12351245 "Token Probabilities": "词符概率",
12361246 "Select a token to see alternatives considered by the AI.": "选择一个词符来查看 AI 考虑的替代方案。",
12371247 "Reroll with the entire prefix": "Reroll with the entire prefix使用完整前缀重新生成",
12381248 "Not connected to API!": "未连接到API!",
12391249 "Type a message, or /? for help": "键入消息输入想发送的消息或输入 /? 获取帮助",
12401250 "Continue script execution": "继续执行脚本",
12411251 "Pause script execution": "暂停执行脚本",
12421252 "Abort script execution": "中止执行脚本",
@@ -1355,7 +1365,7 @@
13551365 "You are in offline mode. Click on the image below to set the expression.": "您处于离线模式。点击下方图片即可设置表情。",
13561366 "Sprite Folder Override": "表情文件夹覆盖",
13571367 "Use a forward slash to specify a subfolder. Example: _space": "使用正斜杠指定子文件夹。例如:",
13581368 "Upload sprite pack (ZIP)": "上传表情包 (ZIP)",
13591369 "Remove all image overrides": "删除所有图片覆盖",
13601370 "Create new folder in the _space": "创建新文件夹到",
13611371 "folder of your user data directory and name it as the name of the character.": "用户数据目录的文件夹并将其命名为角色的名称。",
@@ -1460,12 +1470,12 @@
14601470 "ext_regex_global_scripts": "全局正则脚本",
14611471 "ext_regex_global_scripts_desc": "影响所有角色,保存在本地设定中",
14621472 "ext_regex_scoped_scripts": "局部正则脚本",
14631473 "ext_regex_disallow_scoped": "Disallow using scoped regex不允许使用局部正则",
14641474 "ext_regex_allow_scoped": "允许使用范围正则表达式允许使用局部正则",
14651475 "ext_regex_scoped_scripts_desc": "只影响当前角色,保存在角色卡片中",
14661476 "Regex Editor": "正则表达式编辑器",
14671477 "Test Mode": "测试模式",
14681478 "ext_regex_desc": "正则是一款使用正则表达式查找“正则”是一个使用“正则表达式”来查找/替换字符串的工具。如果您想了解更多信息,请点击标题旁边的 ?“?”。",
14691479 "Input": "输入",
14701480 "ext_regex_test_input_placeholder": "在此输入...",
14711481 "Output": "输出",
@@ -1566,7 +1576,7 @@
15661576 "Click to set": "点击设置",
15671577 "You can find your API key in the Stability AI dashboard.": "您可以在 Stability AI 仪表板中找到您的 API 密钥。",
15681578 "Style Preset": "风格预设",
15691579 "Prompt Upsampling": "Prompt 提示词增强(Upsampling",
15701580 "Sampling method": "采样方法",
15711581 "Scheduler": "调度器",
15721582 "Resolution": "分辨率",
@@ -1584,7 +1594,7 @@
15841594 "Karras": "Karras",
15851595 "Not all samplers supported.": "并非所有采样器都受支持。",
15861596 "sd_adetailer_face": "Use ADetailer with face model during the generation. The ADetailer extension must be installed on the backend.",
15871597 "Use ADetailer (Face)": "使用 ADetailer (Face)(脸部)",
15881598 "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA 版本的采样器经过修改,在高分辨率下性能更佳。",
15891599 "SMEA": "中小企业协会",
15901600 "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 采样器的 DYN 变体通常会产生更加多样化的输出,但在非常高的分辨率下可能会失败。",
@@ -1627,9 +1637,9 @@
16271637 "Select TTS Provider": "选择 文本转语音 的服务提供商",
16281638 "tts_enabled": "已启用",
16291639 "Narrate user messages": "朗读用户消息",
16301640 "Auto Generation": "Auto Generation自动生成",
16311641 "Requires auto generation to be enabled.": "Requires auto generation to be enabled.需要启用自动生成功能。",
16321642 "Narrate by paragraphs (when streaming)": "Narrate by paragraphs (when streaming)按段朗读(流式播放时)",
16331643 "Only narrate quotes": "只朗读引号内文本",
16341644 "Ignore text, even quotes, inside asterisk": "不朗读所有*星号内文本*,即使其被引号包裹",
16351645 "Narrate only the translated text": "只朗读翻译后文本",
@@ -1658,9 +1668,9 @@
16581668 "Enable for files": "为文件启用",
16591669 "Translate files into English before processing": "处理之前将文件翻译成英文",
16601670 "Message attachments": "消息附件",
16611671 "Size threshold (KB)": "大小阈值 (KB)",
16621672 "Chunk size (chars)": "块大小(字符)",
16631673 "Chunk overlap (%)": "块重叠 (%)",
16641674 "Retrieve chunks": "检索块",
16651675 "Data Bank files": "数据库文件",
16661676 "Injection Template": "注入模板",
@@ -1691,6 +1701,7 @@
16911701 "This will create a new subfolder...": "这将在 /data/ 目录中创建一个新的子文件夹,以用户的句柄作为文件夹名称。",
16921702 "Note:": "提示:",
16931703 "this chat is temporary and will be deleted as soon as you leave it.": "此聊天会话是临时的,会在你离开时被删除。",
1704+ "Enter a new display name:": "输入一个新的昵称:",
16941705 "Current Password:": "当前密码:",
16951706 "New Password:": "新密码:",
16961707 "Confirm New Password:": "确认新密码:",
@@ -1711,22 +1722,25 @@
17111722 "chat_rename_1": "输入聊天的新名称:",
17121723 "chat_rename_2": "注意!!使用已有文件名会导致错误!!",
17131724 "chat_rename_3": "此举会将次聊天与标记为“检查点”的聊天解绑。",
17141725 "chat_rename_4": "不需要在结尾添加 '.jsonlJSONL'",
1726+ "Enter Checkpoint Name:": "输入检查点名称:",
1727+ "(Leave empty to auto-generate)": "(留空以自动生成)",
1728+ "The currently existing checkpoint will be unlinked and replaced with the new checkpoint, but can still be found in the Chat Management.": "当前检查点将会被解绑并替换为新的检查点,但仍可在聊天管理中找到。",
17151729 "Include Body Parameters": "包括主体参数",
17161730 "custom_include_body_desc": "聊天完成请求主体中要包含的参数(YAML 对象)\n\n示例:\n- top_k:20\n- repetition_penalty:1.1",
17171731 "Exclude Body Parameters": "排除主体参数",
17181732 "custom_exclude_body_desc": "要从聊天完成请求主体中排除的参数(YAML 数组)\n\n示例:\n- frequency_penalty\n- presence_penalty",
17191733 "Include Request Headers": "包含请求标头",
17201734 "custom_include_headers_desc": "聊天完成请求的附加标头(YAML 对象)\n\n示例:\n- CustomHeader:自定义值\n- AnotherHeader:自定义值",
1721- "Debug Warning": "此类别中的功能仅供高级用户使用。如果您不确定后果,请不要点击任何内容。",
1735+ "Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "此类别中的功能仅供高级用户使用。如果您不确定后果,请不要点击任何内容。",
17221736 "THIS IS PERMANENT!": "此操作不可逆!",
17231737 "Also delete the chat files": "同时删除聊天文件",
17241738 "Are you sure you want to delete this user?": "您确定要删除该用户吗?",
17251739 "Deleting:": "删除:",
17261740 "Also wipe user data.": "也清空用户数据。同时清空用户数据",
17271741 "Warning:": "警告:",
17281742 "This action is irreversible.": "此操作不可逆。",
17291743 "Type the user's handle below to confirm:": "在下面输入用户的名称以确认在下面输入此用户的用户句柄以确认删除操作:",
17301744 "Are you sure you want to duplicate this character?": "你确定要复制这个角色吗?",
17311745 "If you just want to start a new chat with the same character...": "如果你只是想要与此角色开启一个新的聊天,只需点击聊天左下方菜单中的“开始新聊天”按钮。",
17321746 "Forbid Media Override explanation": "当前角色/群聊成员使用外部媒体的能力。",
@@ -1764,11 +1778,11 @@
17641778 "help_format_26": "内联代码",
17651779 "help_format_27": "> 文本",
17661780 "help_format_28": "显示为块引用(请注意 > 后面的空格)",
17671781 "help_format_29": "# 文本",
17681782 "help_format_30": "显示为大标题(注意空格)",
17691783 "help_format_32": "#### 文本",
17701784 "help_format_33": "显示为中等标题(注意空格)",
17711785 "help_format_35": "###### 文本",
17721786 "help_format_36": "显示为小标题(注意空格)",
17731787 "help_1": "您好!请选择您想要详细了解的帮助主题:",
17741788 "help_2": "斜线命令",
@@ -1821,9 +1835,27 @@
18211835 "char_import_8": "RisuRealm 角色(直链)",
18221836 "Supports importing multiple characters.": "支持导入多个角色。",
18231837 "Write each URL or ID into a new line.": "将每个 URL 或 ID 写入新行。",
1824- "Show Raw Prompt": "显示原始提示",
1838+ "Enter the Git URL of the extension to install": "输入扩展程序的 Git URL 以安装",
18251839 "Copy PromptDisclaimer:": "复制提示免责声明:",
1826- "Show Prompt Differences": "显示提示差异",
1840+ "Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.": "使用外部的扩展程序可能存在意料外的副作用和安全隐患。在导入扩展程序前,请一定确认其来源可信。我们不为第三方扩展程序造成的任何损失负责。",
1841+ "Prompt Itemization": "将提示词分条",
1842+ "Show Raw Prompt": "显示原始提示词",
1843+ "Copy Prompt": "复制提示词",
1844+ "Show Prompt Differences": "显示提示词差异",
1845+ "API/Model:": "API/模型:",
1846+ "Preset:": "预设:",
1847+ "Tokenizer:": "分词器:",
1848+ "Only the white numbers really matter. All numbers are estimates. Grey color items may not have been included in the context due to certain prompt format settings.": "只有白色的数字作数。所有数字均为估算。\n 灰色的数字可能因特定的提示词处理规则而被排除在外。",
1849+ "System Info:": "系统信息:",
1850+ "Prompt Tokens:": "提示词Token:",
1851+ "World Info:": "世界书:",
1852+ "Chat History:": "聊天记录:",
1853+ "Extensions:": "扩展程序:",
1854+ "Bias:": "Bias:",
1855+ "Total Tokens in Prompt:": "提示词的总Token数量:",
1856+ "Max Context": "最大上下文:",
1857+ "(Context Size - Response Length)": "(上下文长度 - 回复长度)",
1858+ ":": ":",
18271859 "System-wide Replacement Macros (in order of evaluation):": "系统范围的替换宏(按评估顺序):",
18281860 "help_macros_1": "仅适用于斜线命令批处理。替换为上一个命令的返回结果。",
18291861 "help_macros_2": "仅插入一个换行符。",
@@ -1913,7 +1945,9 @@
19131945 "help_macros_68": "替换为全局变量“name”的值减 1 的结果",
19141946 "help_macros_69": "替换为范围变量“name”的值",
19151947 "help_macros_70": "用范围变量“name”的索引处的项目值(对于数组/列表或对象/字典)替换",
1948+ "Choose what to export": "选择您想要导出什么:",
19161949 "{{name}}": "{{name}}",
1950+ "Choose what to import": "选择您想要导入什么:",
19171951 "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可稍后在 /backups 文件夹中恢复此聊天文件。",
19181952 "Also delete the current chat file": "同时删除当前聊天文件",
19191953 "Persona Lorebook for": "Persona Lorebook for",
@@ -1938,8 +1972,13 @@
19381972 "If you have sufficient credits, please try again later.": "若您有足够的余额,请稍后再试。",
19391973 "Are you sure you want to reset your settings to factory defaults?": "您确定要将您的设置重置为出厂默认设置吗?",
19401974 "Don't forget to save a snapshot of your settings before proceeding.": "在继续之前,不要忘记保存您的设置快照。",
1975+ "Enter your password below to confirm:": "输入您的密码以确认:",
19411976 "Chat Scenario Override": "聊天场景覆盖",
19421977 "Remove": "移除",
1978+ "Unique to this chat.": "Unique to this chat.",
1979+ "All group members will use the following scenario text instead of what is specified in their character cards.": "All group members will use the following scenario text instead of what is specified in their character cards.",
1980+ "The following scenario text will be used instead of the value set in the character card.": "The following scenario text will be used instead of the value set in the character card.",
1981+ "Checkpoints inherit the scenario override from their parent, and can be changed individually after that.": "Checkpoints inherit the scenario override from their parent, and can be changed individually after that.",
19431982 "Settings Snapshots": "设置快照",
19441983 "Record a snapshot of your current settings.": "记录当前设置的快照。",
19451984 "Make a Snapshot": "制作快照",
@@ -1962,6 +2001,7 @@
19622001 "Click on the folder icon to use this tag as a folder.": "点击文件夹图标来将此标签作为一个文件夹。",
19632002 "Use alphabetical sorting": "按字母顺序排列",
19642003 "tags_sorting_desc": "启用后,标签在创建或重命名时会自动按字母顺序排序。\n禁用后,新标签会追加到末尾。\n\n如果通过拖动手动重新排列标签,则自动排序将被禁用。",
2004+ "Are you sure you want to delete the theme?": "你确定要删除这个主题吗?",
19652005 "Hi,": "嗨,",
19662006 "To enable multi-account features, restart the SillyTavern server with": "要启用多帐户功能,请使用以下命令重新启动 SillyTavern 服务器",
19672007 "set to true in the config.yaml file.": "在 config.yaml 文件中设置为 true。",
@@ -1982,6 +2022,8 @@
19822022 "Reset Settings": "重置设置",
19832023 "Wipe all user data and reset your account to factory settings.": "删除所有用户数据并将您的账号重置为默认设置。",
19842024 "Reset Everything": "重置一切",
2025+ "This will delete all your settings and data. There will be no undo button. Make sure you have a backup before proceeding.": "This will delete all your settings and data. There will be no undo button.\n Make sure you have a backup before proceeding.",
2026+ "Account reset code has been posted to the server console.": "Account reset code has been posted to the server console.",
19852027 "Reset Code:": "重置代码:",
19862028 "Want to update?": "获取最新版本",
19872029 "How to start chatting?": "如何快速开始聊天?",
public/locales/zh-tw.json+2 -2
@@ -880,7 +880,7 @@
880880 "popup-button-no": "取消",
881881 "popup-button-cancel": "關閉",
882882 "popup-button-import": "匯入",
883883 "Advanced DefininitionsDefinitions": "- 進階定義",
884884 "Prompt Overrides": "提示詞覆寫",
885885 "(For Chat Completion and Instruct Mode)": "(用於聊天補全和指令模式)",
886886 "Insert {{original}} into either box to include the respective default prompt from system settings.": "在任一框中插入 {{original}} 以包含系統設定中的預設提示詞。",
@@ -1454,7 +1454,7 @@
14541454 "Any contents here will replace the default Post-History Instructions used for this character. (v2 specpost_history_instructions)": "此處填入的內容將取代該角色的默認聊天歷史後指示(Post-History Instructions)。\n(v2 格式:specpost_history_instructions)",
14551455 "comma delimited,no spaces between": "逗號分割,無需空格",
14561456 "e.g. black-forest-labs/FLUX.1-dev": "例如:black-forest-labs/FLUX.1-dev",
14571457 "Example: gpt-3.5-turbo4o": "例如:gpt-3.5-turbo4o",
14581458 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",
14591459 "popup-button-crop": "裁剪",
14601460 "(disabled when max recursion steps are used)": "(當最大遞歸步驟數使用時將停用)",
public/script.js+117 -37
@@ -574,7 +574,7 @@ export const DEFAULT_SAVE_EDIT_TIMEOUT = debounce_timeout.relaxed;
574574/** @type {debounce_timeout} The debounce timeout used for printing. debounce_timeout.quick: 100 ms */
575575export const DEFAULT_PRINT_TIMEOUT = debounce_timeout.quick;
576576
577577export const saveSettingsDebounced = debounce((loopCounter = 0) => saveSettings(loopCounter), DEFAULT_SAVE_EDIT_TIMEOUT);
578578export const saveCharacterDebounced = debounce(() => $('#create_button').trigger('click'), DEFAULT_SAVE_EDIT_TIMEOUT);
579579
580580/**
@@ -2724,7 +2724,7 @@ export function getStoppingStrings(isImpersonate, isContinue) {
27242724export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, quietImage = null, quietName = null, responseLength = null, force_chid = null) {
27252725 console.log('got into genQuietPrompt');
27262726 const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0;
27272727 let originalResponseLengtheventHook = -1() => {};
27282728 try {
27292729 /** @type {GenerateOptions} */
27302730 const options = {
@@ -2736,11 +2736,15 @@ export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, q
27362736 quietName: quietName,
27372737 force_chid: force_chid,
27382738 };
2739- originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1;
2739+ if (responseLengthCustomized) {
2740+ TempResponseLength.save(main_api, responseLength);
2741+ eventHook = TempResponseLength.setupEventHook(main_api);
2742+ }
27402743 return await Generate('quiet', options);
27412744 } finally {
27422745 if (responseLengthCustomized && TempResponseLength.isCustomized()) {
27432746 restoreResponseLengthTempResponseLength.restore(main_api, originalResponseLength);
2747+ TempResponseLength.removeEventHook(main_api, eventHook);
27442748 }
27452749 }
27462750}
@@ -3384,9 +3388,9 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
33843388
33853389 const abortController = new AbortController();
33863390 const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0;
3387- let originalResponseLength = -1;
33883391 const isInstruct = power_user.instruct.enabled && api !== 'openai' && api !== 'novel' && !instructOverride;
33893392 const isQuiet = true;
3393+ let eventHook = () => {};
33903394
33913395 if (systemPrompt) {
33923396 systemPrompt = substituteParams(systemPrompt);
@@ -3400,7 +3404,9 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
34003404 prompt = isInstruct ? (prompt + formatInstructModePrompt(name2, false, '', name1, name2, isQuiet, quietToLoud)) : (prompt + '\n');
34013405
34023406 try {
3403- originalResponseLength = responseLengthCustomized ? saveResponseLength(api, responseLength) : -1;
3407+ if (responseLengthCustomized) {
3408+ TempResponseLength.save(api, responseLength);
3409+ }
34043410 let generateData = {};
34053411
34063412 switch (api) {
@@ -3413,20 +3419,24 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
34133419 const koboldSettings = koboldai_settings[koboldai_setting_names[preset_settings]];
34143420 generateData = getKoboldGenerationData(prompt, koboldSettings, amount_gen, max_context, isHorde, 'quiet');
34153421 }
3422+ TempResponseLength.restore(api);
34163423 break;
34173424 case 'novel': {
34183425 const novelSettings = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]];
34193426 generateData = getNovelGenerationData(prompt, novelSettings, amount_gen, false, false, null, 'quiet');
3427+ TempResponseLength.restore(api);
34203428 break;
34213429 }
34223430 case 'textgenerationwebui':
34233431 generateData = getTextGenGenerationData(prompt, amount_gen, false, false, null, 'quiet');
3432+ TempResponseLength.restore(api);
34243433 break;
34253434 case 'openai': {
34263435 generateData = [{ role: 'user', content: prompt.trim() }];
34273436 if (systemPrompt) {
34283437 generateData.unshift({ role: 'system', content: systemPrompt.trim() });
34293438 }
3439+ eventHook = TempResponseLength.setupEventHook(api);
34303440 } break;
34313441 }
34323442
@@ -3468,41 +3478,100 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
34683478
34693479 return message;
34703480 } finally {
34713481 if (responseLengthCustomized && TempResponseLength.isCustomized()) {
34723482 restoreResponseLengthTempResponseLength.restore(api, originalResponseLength);
3483+ TempResponseLength.removeEventHook(api, eventHook);
34733484 }
34743485 }
34753486}
34763487
3477-/**
3488+class TempResponseLength {
3478- * Temporarily change the response length for the specified API.
3489+ static #originalResponseLength = -1;
3479- * @param {string} api API to use.
3490+ static #lastApi = null;
3480- * @param {number} responseLength Target response length.
3491+
3481- * @returns {number} The original response length.
3492+ static isCustomized() {
3482- */
3493+ return this.#originalResponseLength > -1;
3483-function saveResponseLength(api, responseLength) {
3484- let oldValue = -1;
3485- if (api === 'openai') {
3486- oldValue = oai_settings.openai_max_tokens;
3487- oai_settings.openai_max_tokens = responseLength;
3488- } else {
3489- oldValue = amount_gen;
3490- amount_gen = responseLength;
34913494 }
3492- return oldValue;
3493-}
34943495
34953496 /**
34963497 * RestoreSave the originalcurrent response length for the specified API.
34973498 * @param {string} api API to use.identifier
34983499 * @param {number} responseLength TargetNew response length.
3499- * @returns {void}
3500+ */
3500- */
3501+ static save(api, responseLength) {
35013502function if restoreResponseLength(api, responseLength=== 'openai') {
3502- if (api === 'openai') {
3503+ this.#originalResponseLength = oai_settings.openai_max_tokens;
35033504 oai_settings.openai_max_tokens = responseLength;
35043505 } else {
3505- amount_gen = responseLength;
3506+ this.#originalResponseLength = amount_gen;
3507+ amount_gen = responseLength;
3508+ }
3509+
3510+ this.#lastApi = api;
3511+ console.log('[TempResponseLength] Saved original response length:', TempResponseLength.#originalResponseLength);
3512+ }
3513+
3514+ /**
3515+ * Restore the original response length for the specified API.
3516+ * @param {string|null} api API identifier
3517+ * @returns {void}
3518+ */
3519+ static restore(api) {
3520+ if (this.#originalResponseLength === -1) {
3521+ return;
3522+ }
3523+ if (!api && this.#lastApi) {
3524+ api = this.#lastApi;
3525+ }
3526+ if (api === 'openai') {
3527+ oai_settings.openai_max_tokens = this.#originalResponseLength;
3528+ } else {
3529+ amount_gen = this.#originalResponseLength;
3530+ }
3531+
3532+ console.log('[TempResponseLength] Restored original response length:', this.#originalResponseLength);
3533+ this.#originalResponseLength = -1;
3534+ this.#lastApi = null;
3535+ }
3536+
3537+ /**
3538+ * Sets up an event hook to restore the original response length when the event is emitted.
3539+ * @param {string} api API identifier
3540+ * @returns {function(): void} Event hook function
3541+ */
3542+ static setupEventHook(api) {
3543+ const eventHook = () => {
3544+ if (this.isCustomized()) {
3545+ this.restore(api);
3546+ }
3547+ };
3548+
3549+ switch (api) {
3550+ case 'openai':
3551+ eventSource.once(event_types.CHAT_COMPLETION_SETTINGS_READY, eventHook);
3552+ break;
3553+ default:
3554+ eventSource.once(event_types.GENERATE_AFTER_DATA, eventHook);
3555+ break;
3556+ }
3557+
3558+ return eventHook;
3559+ }
3560+
3561+ /**
3562+ * Removes the event hook for the specified API.
3563+ * @param {string} api API identifier
3564+ * @param {function(): void} eventHook Previously set up event hook
3565+ */
3566+ static removeEventHook(api, eventHook) {
3567+ switch (api) {
3568+ case 'openai':
3569+ eventSource.removeListener(event_types.CHAT_COMPLETION_SETTINGS_READY, eventHook);
3570+ break;
3571+ default:
3572+ eventSource.removeListener(event_types.GENERATE_AFTER_DATA, eventHook);
3573+ break;
3574+ }
35063575 }
35073576}
35083577
@@ -6865,12 +6934,23 @@ function selectKoboldGuiPreset() {
68656934 .trigger('change');
68666935}
68676936
68686937export async function saveSettings(typeloopCounter = 0) {
68696938 if (!settingsReady) {
68706939 console.warn('Settings not ready, aborting save');
68716940 return;
68726941 }
68736942
6943+ const MAX_RETRIES = 3;
6944+ if (TempResponseLength.isCustomized()) {
6945+ if (loopCounter < MAX_RETRIES) {
6946+ console.warn('Response length is currently being overridden, scheduling another save');
6947+ saveSettingsDebounced(++loopCounter);
6948+ return;
6949+ }
6950+ console.error('Response length is currently being overridden, but the save loop has reached the maximum number of retries');
6951+ TempResponseLength.restore(null);
6952+ }
6953+
68746954 //console.log('Entering settings with name1 = '+name1);
68756955 return jQuery.ajax({
68766956 type: 'POST',
public/scripts/extensions.js+11 -11
@@ -682,9 +682,9 @@ function getExtensionData(extension) {
682682 * @return {string} - The HTML string for the module information.
683683 */
684684function getModuleInformation() {
685685 let moduleInfo = modules.length ? `<p>${DOMPurify.sanitize(modules.join(', '))}</p>` : '<p class="failure">' + t`Not connected to the API!` + '</p>';
686686 return `
687687 <h3>` + t`Modules provided by your Extras API:` + `</h3>
688688 ${moduleInfo}
689689 `;
690690}
@@ -703,11 +703,11 @@ async function showExtensionsDetails() {
703703 initialScrollTop = oldPopup.content.scrollTop;
704704 await oldPopup.completeCancelled();
705705 }
706706 const htmlDefault = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Built-in Extensions:` + '</h3></div>');
707707 const htmlExternal = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Installed Extensions:` + '</h3></div>');
708708 const htmlLoading = $(`<div class="flex-container alignItemsCenter justifyCenter marginTop10 marginBot5">
709709 <i class="fa-solid fa-spinner fa-spin"></i>
710710 <span>` + t`Loading third-party extensions... Please wait...` + `</span>
711711 </div>`);
712712
713713 htmlExternal.append(htmlLoading);
@@ -728,7 +728,7 @@ async function showExtensionsDetails() {
728728
729729 /** @type {import('./popup.js').CustomPopupButton} */
730730 const updateAllButton = {
731731 text: 't`Update all'`,
732732 appendAtEnd: true,
733733 action: async () => {
734734 requiresReload = true;
@@ -740,7 +740,7 @@ async function showExtensionsDetails() {
740740 let waitingForSave = false;
741741
742742 const popup = new Popup(html, POPUP_TYPE.TEXT, '', {
743743 okButton: 't`Close'`,
744744 wide: true,
745745 large: true,
746746 customButtons: [updateAllButton],
@@ -833,7 +833,7 @@ async function updateExtension(extensionName, quiet) {
833833 toastr.success('Extension is already up to date');
834834 }
835835 } else {
836836 toastr.success(t`Extension ${extensionName} updated to ${data.shortCommitHash}`, 't`Reload the page to apply updates'`);
837837 }
838838 } catch (error) {
839839 console.error('Error:', error);
@@ -1001,7 +1001,7 @@ export async function installExtension(url, global) {
10011001 }
10021002
10031003 const response = await request.json();
10041004 toastr.success(t`Extension "'${response.display_name}"' by ${response.author} (version ${response.version}) has been installed successfully!`, 't`Extension installation successful'`);
10051005 console.debug(`Extension "${response.display_name}" has been installed successfully at ${response.extensionPath}`);
10061006 await loadExtensionSettings({}, false, false);
10071007 await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED);
@@ -1175,7 +1175,7 @@ async function checkForExtensionUpdates(force) {
11751175 await Promise.allSettled(promises);
11761176
11771177 if (updatesAvailable.length > 0) {
11781178 toastr.info(`${updatesAvailable.map(x => `• ${x}`).join('\n')}`, 't`Extension updates available'`);
11791179 }
11801180}
11811181
@@ -1189,7 +1189,7 @@ async function autoUpdateExtensions(forceAll) {
11891189 return;
11901190 }
11911191
11921192 const banner = toastr.info('t`Auto-updating extensions. This may take several minutes.'`, 't`Please wait...'`, { timeOut: 10000, extendedTimeOut: 10000 });
11931193 const isCurrentUserAdmin = isAdmin();
11941194 const promises = [];
11951195 for (const [id, manifest] of Object.entries(manifests)) {
public/scripts/extensions/connection-manager/edit.html+2 -2
@@ -1,10 +1,10 @@
11<div>
22 <h3 data-i18n="Included settings:">Included settings:</h3>
33 <div class="justifyLeft flex-container flexFlowColumn flexNoGap">
44 {{#each settings}}
55 <label class="checkbox_label">
66 <input type="checkbox" value="{{@key}}" name="exclude"{{#if this}} checked{{/if}}>
77 <span data-i18n="{{@key}}">{{@key}}</span>
88 </label>
99 {{/each}}
1010 </div>
public/scripts/extensions/connection-manager/profile.html+2 -2
@@ -12,8 +12,8 @@
1212 </div>
1313 <div class="marginTop5">
1414 <small>
1515 <b data-i18n="Hint:">Hint:</b>
1616 <i data-i18n="Click on the setting name to omit it from the profile.">Click on the setting name to omit it from the profile.</i>
1717 </small>
1818 </div>
1919 <h3 data-i18n="Enter a name:">
public/scripts/extensions/quick-reply/html/settings.html+2 -0
@@ -46,10 +46,12 @@
4646 <div class="qr--title" data-i18n="Edit Quick Replies">Edit Quick Replies</div>
4747 <div class="qr--actions">
4848 <select id="qr--set" class="text_pole"></select>
49+ <div class="qr--add menu_button menu_button_icon fa-solid fa-pencil" id="qr--set-rename" title="Rename quick reply set"></div>
4950 <div class="qr--add menu_button menu_button_icon fa-solid fa-plus" id="qr--set-new" title="Create new quick reply set"></div>
5051 <div class="qr--add menu_button menu_button_icon fa-solid fa-file-import" id="qr--set-import" title="Import quick reply set"></div>
5152 <input type="file" id="qr--set-importFile" accept=".json" hidden>
5253 <div class="qr--add menu_button menu_button_icon fa-solid fa-file-export" id="qr--set-export" title="Export quick reply set"></div>
54+ <div class="qr-add menu_button menu_button_icon fa-solid fa-paste" id="qr--set-duplicate" title="Duplicate quick reply set"></div>
5355 <div class="qr--del menu_button menu_button_icon fa-solid fa-trash redWarningBG" id="qr--set-delete" title="Delete quick reply set"></div>
5456 </div>
5557 </div>
public/scripts/extensions/quick-reply/src/ui/SettingsUi.js+82 -6
@@ -1,4 +1,4 @@
11import { callPopupPopup } from '../../../../../scriptpopup.js';
22import { getSortableDelay } from '../../../../utils.js';
33import { log, warn } from '../../index.js';
44import { QuickReply } from '../QuickReply.js';
@@ -111,6 +111,7 @@ export class SettingsUi {
111111
112112 prepareQrEditor() {
113113 // qr editor
114+ this.dom.querySelector('#qr--set-rename').addEventListener('click', async () => this.renameQrSet());
114115 this.dom.querySelector('#qr--set-new').addEventListener('click', async()=>this.addQrSet());
115116 /**@type {HTMLInputElement}*/
116117 const importFile = this.dom.querySelector('#qr--set-importFile');
@@ -119,7 +120,8 @@ export class SettingsUi {
119120 importFile.value = null;
120121 });
121122 this.dom.querySelector('#qr--set-import').addEventListener('click', ()=>importFile.click());
122123 this.dom.querySelector('#qr--set-export').addEventListener('click', async () => this.exportQrSet());
124+ this.dom.querySelector('#qr--set-duplicate').addEventListener('click', async () => this.duplicateQrSet());
123125 this.dom.querySelector('#qr--set-delete').addEventListener('click', async()=>this.deleteQrSet());
124126 this.dom.querySelector('#qr--set-add').addEventListener('click', async()=>{
125127 this.currentQrSet.addQuickReply();
@@ -279,7 +281,7 @@ export class SettingsUi {
279281 }
280282
281283 async deleteQrSet() {
282284 const confirmed = await callPopupPopup.show.confirm('Delete Quick Reply Set', `Are you sure you want to delete the Quick Reply Set "${this.currentQrSet.name}"?<br>This cannot be undone.`, 'confirm');
283285 if (confirmed) {
284286 await this.doDeleteQrSet(this.currentQrSet);
285287 this.rerender();
@@ -303,12 +305,52 @@ export class SettingsUi {
303305 this.settings.save();
304306 }
305307
308+ async renameQrSet() {
309+ const newName = await Popup.show.input('Rename Quick Reply Set', 'Enter a new name:', this.currentQrSet.name);
310+ if (newName && newName.length > 0) {
311+ const existingSet = QuickReplySet.get(newName);
312+ if (existingSet) {
313+ toastr.error(`A Quick Reply Set named "${newName}" already exists.`);
314+ return;
315+ }
316+ const oldName = this.currentQrSet.name;
317+ this.currentQrSet.name = newName;
318+ await this.currentQrSet.save();
319+
320+ // Update it in both set lists
321+ this.settings.config.setList.forEach(set => {
322+ if (set.set.name === oldName) {
323+ set.set.name = newName;
324+ }
325+ });
326+ this.settings.chatConfig?.setList.forEach(set => {
327+ if (set.set.name === oldName) {
328+ set.set.name = newName;
329+ }
330+ });
331+ this.settings.save();
332+
333+ // Update the option in the current selected QR dropdown. All others will be refreshed via the prepare calls below.
334+ /** @type {HTMLOptionElement} */
335+ const option = this.currentSet.querySelector(`#qr--set option[value="${oldName}"]`);
336+ option.value = newName;
337+ option.textContent = newName;
338+
339+ this.currentSet.value = newName;
340+ this.onQrSetChange();
341+ this.prepareGlobalSetList();
342+ this.prepareChatSetList();
343+
344+ console.info(`Quick Reply Set renamed from ""${oldName}" to "${newName}".`);
345+ }
346+ }
347+
306348 async addQrSet() {
307349 const name = await callPopupPopup.show.input('QuickCreate Replya Setnew Name:World Info', 'inputEnter a name for the new Quick Reply Set:');
308350 if (name && name.length > 0) {
309351 const oldQrs = QuickReplySet.get(name);
310352 if (oldQrs) {
311353 const replace = await callPopupPopup.show.confirm('Replace existing World Info', `A Quick Reply Set named "${name}" already exists.<br>Do you want to overwrite the existing Quick Reply Set?<br>The existing set will be deleted. This cannot be undone.`, 'confirm');
312354 if (replace) {
313355 const idx = QuickReplySet.list.indexOf(oldQrs);
314356 await this.doDeleteQrSet(oldQrs);
@@ -369,7 +411,7 @@ export class SettingsUi {
369411 qrs.init();
370412 const oldQrs = QuickReplySet.get(props.name);
371413 if (oldQrs) {
372414 const replace = await callPopupPopup.show.confirm('Replace existing World Info', `A Quick Reply Set named "${qrs.name}" already exists.<br>Do you want to overwrite the existing Quick Reply Set?<br>The existing set will be deleted. This cannot be undone.`, 'confirm');
373415 if (replace) {
374416 const idx = QuickReplySet.list.indexOf(oldQrs);
375417 await this.doDeleteQrSet(oldQrs);
@@ -421,6 +463,40 @@ export class SettingsUi {
421463 URL.revokeObjectURL(url);
422464 }
423465
466+ async duplicateQrSet() {
467+ const newName = await Popup.show.input('Duplicate Quick Reply Set', 'Enter a name for the new Quick Reply Set:', `${this.currentQrSet.name} (Copy)`);
468+ if (newName && newName.length > 0) {
469+ const existingSet = QuickReplySet.get(newName);
470+ if (existingSet) {
471+ toastr.error(`A Quick Reply Set named "${newName}" already exists.`);
472+ return;
473+ }
474+ const newQrSet = QuickReplySet.from(JSON.parse(JSON.stringify(this.currentQrSet)));
475+ newQrSet.name = newName;
476+ newQrSet.qrList = this.currentQrSet.qrList.map(qr => QuickReply.from(JSON.parse(JSON.stringify(qr))));
477+ newQrSet.addQuickReply();
478+ const idx = QuickReplySet.list.findIndex(it => it.name.toLowerCase().localeCompare(newName.toLowerCase()) == 1);
479+ if (idx > -1) {
480+ QuickReplySet.list.splice(idx, 0, newQrSet);
481+ } else {
482+ QuickReplySet.list.push(newQrSet);
483+ }
484+ const opt = document.createElement('option'); {
485+ opt.value = newQrSet.name;
486+ opt.textContent = newQrSet.name;
487+ if (idx > -1) {
488+ this.currentSet.children[idx].insertAdjacentElement('beforebegin', opt);
489+ } else {
490+ this.currentSet.append(opt);
491+ }
492+ }
493+ this.currentSet.value = newName;
494+ this.onQrSetChange();
495+ this.prepareGlobalSetList();
496+ this.prepareChatSetList();
497+ }
498+ }
499+
424500 selectQrSet(qrs) {
425501 this.currentSet.value = qrs.name;
426502 this.onQrSetChange();
public/scripts/extensions/vectors/index.js+36 -4
@@ -30,6 +30,8 @@ import { textgen_types, textgenerationwebui_settings } from '../../textgen-setti
3030import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
3131import { SlashCommand } from '../../slash-commands/SlashCommand.js';
3232import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
33+import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
34+import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js';
3335import { callGenericPopup, POPUP_RESULT, POPUP_TYPE } from '../../popup.js';
3436import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js';
3537
@@ -1613,25 +1615,55 @@ jQuery(async () => {
16131615 callback: async (args, query) => {
16141616 const clamp = (v) => Number.isNaN(v) ? null : Math.min(1, Math.max(0, v));
16151617 const threshold = clamp(Number(args?.threshold ?? settings.score_threshold));
1618+ const validateCount = (v) => Number.isNaN(v) || !Number.isInteger(v) || v < 1 ? null : v;
1619+ const count = validateCount(Number(args?.count)) ?? settings.chunk_count_db;
16161620 const source = String(args?.source ?? '');
16171621 const attachments = source ? getDataBankAttachmentsForSource(source, false) : getDataBankAttachments(false);
16181622 const collectionIds = await ingestDataBankAttachments(String(source));
16191623 const queryResults = await queryMultipleCollections(collectionIds, String(query), settings.chunk_count_dbcount, threshold);
1620-
1624+
16211625 // Map collection IDs to fileGet URLs
16221626 const urls = Object
16231627 .keys(queryResults)
16241628 .map(x => attachments.find(y => getFileCollectionId(y.url) === x))
16251629 .filter(x => x)
16261630 .map(x => x.url);
1631+
1632+ // Gets the actual text content of chunks
1633+ const getChunksText = () => {
1634+ let textResult = '';
1635+ for (const collectionId in queryResults) {
1636+ const metadata = queryResults[collectionId].metadata?.filter(x => x.text)?.sort((a, b) => a.index - b.index)?.map(x => x.text)?.filter(onlyUnique) || [];
1637+ textResult += metadata.join('\n') + '\n\n';
1638+ }
1639+ return textResult;
1640+ };
1641+
1642+ if (args.return === 'chunks') {
1643+ return getChunksText();
1644+ }
16271645
1628- return JSON.stringify(urls);
1646+ // @ts-ignore
1647+ return slashCommandReturnHelper.doReturn(args.return ?? 'object', urls, { objectToStringFunc: list => list.join('\n') });
1648+
16291649 },
16301650 aliases: ['databank-search', 'data-bank-search'],
16311651 helpString: 'Search the Data Bank for a specific query using vector similarity. Returns a list of file URLs with the most relevant content.',
16321652 namedArgumentList: [
16331653 new SlashCommandNamedArgument('threshold', 'Threshold for the similarity score in the [0, 1] range. Uses the global config value if not set.', ARGUMENT_TYPE.NUMBER, false, false, ''),
1654+ new SlashCommandNamedArgument('count', 'Maximum number of query results to return.', ARGUMENT_TYPE.NUMBER, false, false, ''),
16341655 new SlashCommandNamedArgument('source', 'Optional filter for the attachments by source.', ARGUMENT_TYPE.STRING, false, false, '', ['global', 'character', 'chat']),
1656+ SlashCommandNamedArgument.fromProps({
1657+ name: 'return',
1658+ description: 'How you want the return value to be provided',
1659+ typeList: [ARGUMENT_TYPE.STRING],
1660+ defaultValue: 'object',
1661+ enumList: [
1662+ new SlashCommandEnumValue('chunks', 'Return the actual content chunks', enumTypes.enum, '{}'),
1663+ ...slashCommandReturnHelper.enumList({ allowObject: true })
1664+ ],
1665+ forceEnum: true,
1666+ })
16351667 ],
16361668 unnamedArgumentList: [
16371669 new SlashCommandArgument('Query to search by.', ARGUMENT_TYPE.STRING, true, false),
public/scripts/macros.js+30 -1
@@ -26,6 +26,12 @@ Handlebars.registerHelper('helperMissing', function () {
2626 * @typedef {(nonce: string) => string} MacroFunction
2727 */
2828
29+/**
30+ * @typedef {Object} CustomMacro
31+ * @property {string} key - Macro name (key)
32+ * @property {string} description - Optional description of the macro
33+ */
34+
2935export class MacrosParser {
3036 /**
3137 * A map of registered macros.
@@ -34,11 +40,28 @@ export class MacrosParser {
3440 static #macros = new Map();
3541
3642 /**
43+ * A map of macro descriptions.
44+ * @type {Map<string, string>}
45+ */
46+ static #descriptions = new Map();
47+
48+ /**
49+ * Returns an iterator over all registered macros.
50+ * @returns {IterableIterator<CustomMacro>}
51+ */
52+ static [Symbol.iterator] = function* () {
53+ for (const macro of MacrosParser.#macros.keys()) {
54+ yield { key: macro, description: MacrosParser.#descriptions.get(macro) };
55+ }
56+ };
57+
58+ /**
3759 * Registers a global macro that can be used anywhere where substitution is allowed.
3860 * @param {string} key Macro name (key)
3961 * @param {string|MacroFunction} value A string or a function that returns a string
62+ * @param {string} [description] Optional description of the macro
4063 */
4164 static registerMacro(key, value, description = '') {
4265 if (typeof key !== 'string') {
4366 throw new Error('Macro key must be a string');
4467 }
@@ -64,6 +87,10 @@ export class MacrosParser {
6487 }
6588
6689 this.#macros.set(key, value);
90+
91+ if (typeof description === 'string' && description) {
92+ this.#descriptions.set(key, description);
93+ }
6794 }
6895
6996 /**
@@ -88,6 +115,8 @@ export class MacrosParser {
88115 if (!deleted) {
89116 console.warn(`Macro ${key} was not registered`);
90117 }
118+
119+ this.#descriptions.delete(key);
91120 }
92121
93122 /**
public/scripts/openai.js+2 -2
@@ -5491,8 +5491,8 @@ export function initOpenAI() {
54915491
54925492 if (!isMobile()) {
54935493 $('#model_openrouter_select').select2({
54945494 placeholder: 't`Select a model'`,
54955495 searchInputPlaceholder: 't`Search models...'`,
54965496 searchInputCssClass: 'text_pole',
54975497 width: '100%',
54985498 templateResult: getOpenRouterModelTemplate,
public/scripts/slash-commands/SlashCommandParser.js+6 -0
@@ -22,6 +22,8 @@ import { SlashCommandBreakPoint } from './SlashCommandBreakPoint.js';
2222import { SlashCommandDebugController } from './SlashCommandDebugController.js';
2323import { commonEnumProviders } from './SlashCommandCommonEnumsProvider.js';
2424import { SlashCommandBreak } from './SlashCommandBreak.js';
25+import { MacrosParser } from '../macros.js';
26+import { t } from '../i18n.js';
2527
2628/** @typedef {import('./SlashCommand.js').NamedArgumentsCapture} NamedArgumentsCapture */
2729/** @typedef {import('./SlashCommand.js').NamedArguments} NamedArguments */
@@ -494,6 +496,10 @@ export class SlashCommandParser {
494496 li.querySelector('tt').textContent,
495497 (li.querySelector('tt').remove(),li.innerHTML),
496498 ));
499+ for (const macro of MacrosParser) {
500+ if (options.find(it => it.name === macro.key)) continue;
501+ options.push(new MacroAutoCompleteOption(macro.key, `{{${macro.key}}}`, macro.description || t`No description provided`));
502+ }
497503 const result = new AutoCompleteNameResult(
498504 macro.name,
499505 macro.start + 2,
public/scripts/textgen-models.js+21 -20
@@ -5,6 +5,7 @@ import { textgenerationwebui_settings as textgen_settings, textgen_types } from
55import { tokenizers } from './tokenizers.js';
66import { renderTemplateAsync } from './templates.js';
77import { POPUP_TYPE, callGenericPopup } from './popup.js';
8+import { t } from './i18n.js';
89
910let mancerModels = [];
1011let togetherModels = [];
@@ -936,71 +937,71 @@ export function initTextGenModels() {
936937
937938 if (!isMobile()) {
938939 $('#mancer_model').select2({
939940 placeholder: 't`Select a model'`,
940941 searchInputPlaceholder: 't`Search models...'`,
941942 searchInputCssClass: 'text_pole',
942943 width: '100%',
943944 templateResult: getMancerModelTemplate,
944945 });
945946 $('#model_togetherai_select').select2({
946947 placeholder: 't`Select a model'`,
947948 searchInputPlaceholder: 't`Search models...'`,
948949 searchInputCssClass: 'text_pole',
949950 width: '100%',
950951 templateResult: getTogetherModelTemplate,
951952 });
952953 $('#ollama_model').select2({
953954 placeholder: 't`Select a model'`,
954955 searchInputPlaceholder: 't`Search models...'`,
955956 searchInputCssClass: 'text_pole',
956957 width: '100%',
957958 });
958959 $('#tabby_model').select2({
959960 placeholder: 't`[Currently loaded]'`,
960961 searchInputPlaceholder: 't`Search models...'`,
961962 searchInputCssClass: 'text_pole',
962963 width: '100%',
963964 allowClear: true,
964965 });
965966 $('#model_infermaticai_select').select2({
966967 placeholder: 't`Select a model'`,
967968 searchInputPlaceholder: 't`Search models...'`,
968969 searchInputCssClass: 'text_pole',
969970 width: '100%',
970971 templateResult: getInfermaticAIModelTemplate,
971972 });
972973 $('#model_dreamgen_select').select2({
973974 placeholder: 't`Select a model'`,
974975 searchInputPlaceholder: 't`Search models...'`,
975976 searchInputCssClass: 'text_pole',
976977 width: '100%',
977978 templateResult: getDreamGenModelTemplate,
978979 });
979980 $('#openrouter_model').select2({
980981 placeholder: 't`Select a model'`,
981982 searchInputPlaceholder: 't`Search models...'`,
982983 searchInputCssClass: 'text_pole',
983984 width: '100%',
984985 templateResult: getOpenRouterModelTemplate,
985986 });
986987 $('#vllm_model').select2({
987988 placeholder: 't`Select a model'`,
988989 searchInputPlaceholder: 't`Search models...'`,
989990 searchInputCssClass: 'text_pole',
990991 width: '100%',
991992 templateResult: getVllmModelTemplate,
992993 });
993994 $('#aphrodite_model').select2({
994995 placeholder: 't`Select a model'`,
995996 searchInputPlaceholder: 't`Search models...'`,
996997 searchInputCssClass: 'text_pole',
997998 width: '100%',
998999 templateResult: getAphroditeModelTemplate,
9991000 });
10001001 providersSelect.select2({
10011002 sorter: data => data.sort((a, b) => a.text.localeCompare(b.text)),
10021003 placeholder: 't`Select providers. No selection = all providers.'`,
10031004 searchInputPlaceholder: 't`Search providers...'`,
10041005 searchInputCssClass: 'text_pole',
10051006 width: '100%',
10061007 closeOnSelect: false,
public/scripts/world-info.js+18 -17
@@ -20,6 +20,7 @@ import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
2020import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js';
2121import { StructuredCloneMap } from './util/StructuredCloneMap.js';
2222import { renderTemplateAsync } from './templates.js';
23+import { t } from './i18n.js';
2324
2425export const world_info_insertion_strategy = {
2526 evenly: 0,
@@ -909,21 +910,21 @@ function registerWorldInfoSlashCommands() {
909910
910911 async function getEntriesFromFile(file) {
911912 if (!file || !world_names.includes(file)) {
912913 toastr.warning('t`Valid World Info file name is required'`);
913914 return '';
914915 }
915916
916917 const data = await loadWorldInfo(file);
917918
918919 if (!data || !('entries' in data)) {
919920 toastr.warning('t`World Info file has an invalid format'`);
920921 return '';
921922 }
922923
923924 const entries = Object.values(data.entries);
924925
925926 if (!entries || entries.length === 0) {
926927 toastr.warning('t`World Info file has no entries'`);
927928 return '';
928929 }
929930
@@ -951,7 +952,7 @@ function registerWorldInfoSlashCommands() {
951952 name = String(name ?? '') || context.characters[context.characterId]?.avatar || null;
952953 const character = findChar({ name });
953954 if (!character) {
954955 toastr.error('t`Character not found.'`);
955956 return '';
956957 }
957958 const books = [];
@@ -977,7 +978,7 @@ function registerWorldInfoSlashCommands() {
977978 const chatId = getCurrentChatId();
978979
979980 if (!chatId) {
980981 toastr.warning('t`Open a chat to get a name of the chat-bound lorebook'`);
981982 return '';
982983 }
983984
@@ -4773,7 +4774,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) {
47734774 const bookName = characters[chid]?.data?.character_book?.name || `${characters[chid]?.name}'s Lorebook`;
47744775
47754776 if (!skipPopup) {
47764777 const confirmation = await Popup.show.confirm(t`Are you sure you want to import "'${bookName}"'?`, world_names.includes(bookName) ? 't`It will overwrite the World/Lorebook with the same name.'` : '');
47774778 if (!confirmation) {
47784779 return;
47794780 }
@@ -4785,7 +4786,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) {
47854786 await updateWorldInfoList();
47864787 $('#character_world').val(bookName).trigger('change');
47874788
47884789 toastr.success(t`The world "'${bookName}"' has been imported and linked to the character successfully.`, 't`World/Lorebook imported'`);
47894790
47904791 const newIndex = world_names.indexOf(bookName);
47914792 if (newIndex >= 0) {
@@ -4813,9 +4814,9 @@ export function onWorldInfoChange(args, text) {
48134814 if (selected_world_info.includes(name)) {
48144815 selected_world_info.splice(selected_world_info.indexOf(name), 1);
48154816 wiElement.prop('selected', false);
48164817 if (!silent) toastr.success(t`Deactivated world: ${name}`);
48174818 } else {
48184819 if (!silent) toastr.error(t`World was not active: ${name}`);
48194820 }
48204821 break;
48214822 }
@@ -4823,11 +4824,11 @@ export function onWorldInfoChange(args, text) {
48234824 if (selected_world_info.includes(name)) {
48244825 selected_world_info.splice(selected_world_info.indexOf(name), 1);
48254826 wiElement.prop('selected', false);
48264827 if (!silent) toastr.success(t`Deactivated world: ${name}`);
48274828 } else {
48284829 selected_world_info.push(name);
48294830 wiElement.prop('selected', true);
48304831 if (!silent) toastr.success(t`Activated world: ${name}`);
48314832 }
48324833 break;
48334834 }
@@ -4835,16 +4836,16 @@ export function onWorldInfoChange(args, text) {
48354836 default: {
48364837 selected_world_info.push(name);
48374838 wiElement.prop('selected', true);
48384839 if (!silent) toastr.success(t`Activated world: ${name}`);
48394840 }
48404841 }
48414842 } else {
48424843 if (!silent) toastr.error(t`No world found named: ${worldName}`);
48434844 }
48444845 });
48454846 $('#world_info').trigger('change');
48464847 } else { // if no args, unset all worlds
48474848 if (!silent) toastr.success('t`Deactivated all worlds'`);
48484849 selected_world_info = [];
48494850 $('#world_info').val(null).trigger('change');
48504851 }
@@ -4860,7 +4861,7 @@ export function onWorldInfoChange(args, text) {
48604861 } else {
48614862 const wiElement = getWIElement(existingWorldName);
48624863 wiElement.prop('selected', false);
48634864 toastr.error(t`The world with ${existingWorldName} is invalid or corrupted.`);
48644865 }
48654866 });
48664867 }
@@ -4892,7 +4893,7 @@ export async function importWorldInfo(file) {
48924893 }
48934894
48944895 if (jsonData === undefined || jsonData === null) {
48954896 toastr.error(t`File is not valid: ${file.name}`);
48964897 return;
48974898 }
48984899
@@ -5038,7 +5039,7 @@ jQuery(() => {
50385039
50395040 $('#world_create_button').on('click', async () => {
50405041 const tempName = getFreeWorldName();
50415042 const finalName = await Popup.show.input('t`Create a new World Info'`, 't`Enter a name for the new file:'`, tempName);
50425043
50435044 if (finalName) {
50445045 await createNewWorldInfo(finalName, { interactive: true });
public/style.css+12 -0
@@ -5735,3 +5735,15 @@ body:not(.movingUI) .drawer-content.maximized {
57355735 }
57365736
57375737}
5738+
5739+/* Constrict the scroll of alternate greetings to only the dynamic form section */
5740+.alternate_grettings {
5741+ display: grid;
5742+ grid-template-rows: auto auto auto 1fr;
5743+ max-height: 100%;
5744+ overflow: hidden;
5745+}
5746+
5747+.alternate_greetings_list {
5748+ overflow-y: scroll;
5749+}