Merge branch 'staging' into frFr

5734722c5d050962953507f6edfd9cf554abf7e1

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

29 files changed, +691 -193Showing whitespace changes
public/index.html+10 -10
@@ -2278,7 +2278,7 @@
2278 <h4 data-i18n="Model Providers">Model Providers</h4>2278 <h4 data-i18n="Model Providers">Model Providers</h4>
2279 <select id="openrouter_providers_text" class="openrouter_providers" multiple>2279 <select id="openrouter_providers_text" class="openrouter_providers" multiple>
2280 </select>2280 </select>
2281 <label class="checkbox_label" for="openrouter_allow_fallbacks_textgenerationwebui" title="Automatically chooses an alternative provider if chosen providers can't serve your request.">2281 <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.">
2282 <input id="openrouter_allow_fallbacks_textgenerationwebui" type="checkbox" />2282 <input id="openrouter_allow_fallbacks_textgenerationwebui" type="checkbox" />
2283 <span data-i18n="Allow fallback providers">Allow fallback providers</span>2283 <span data-i18n="Allow fallback providers">Allow fallback providers</span>
2284 </label>2284 </label>
@@ -2902,7 +2902,7 @@
2902 <div>2902 <div>
2903 <h4 data-i18n="Window AI Model">Window AI Model</h4>2903 <h4 data-i18n="Window AI Model">Window AI Model</h4>
2904 <select id="model_windowai_select">2904 <select id="model_windowai_select">
2905 <option value="">Use extension settings</option>2905 <option data-i18n="Use extension settings" value="">Use extension settings</option>
2906 <option value="openai/gpt-3.5-turbo">openai/gpt-3.5-turbo</option>2906 <option value="openai/gpt-3.5-turbo">openai/gpt-3.5-turbo</option>
2907 <option value="openai/gpt-3.5-turbo-16k">openai/gpt-3.5-turbo-16k</option>2907 <option value="openai/gpt-3.5-turbo-16k">openai/gpt-3.5-turbo-16k</option>
2908 <option value="openai/gpt-4">openai/gpt-4</option>2908 <option value="openai/gpt-4">openai/gpt-4</option>
@@ -2977,14 +2977,14 @@
2977 <h4 data-i18n="Model Providers">Model Providers</h4>2977 <h4 data-i18n="Model Providers">Model Providers</h4>
2978 <select id="openrouter_providers_chat" class="openrouter_providers" multiple>2978 <select id="openrouter_providers_chat" class="openrouter_providers" multiple>
2979 </select>2979 </select>
2980 <label class="checkbox_label marginTopBot5" for="openrouter_allow_fallbacks" title="Automatically chooses an alternative provider if chosen providers can't serve your request.">2980 <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.">
2981 <input id="openrouter_allow_fallbacks" type="checkbox" />2981 <input id="openrouter_allow_fallbacks" type="checkbox" />
2982 <span data-i18n="Allow fallback providers">Allow fallback providers</span>2982 <span data-i18n="Allow fallback providers">Allow fallback providers</span>
2983 </label>2983 </label>
2984 </div>2984 </div>
2985 <small class="marginTopBot5">2985 <small class="marginTopBot5">
2986 <i class="fa-solid fa-lightbulb"></i>2986 <i class="fa-solid fa-lightbulb"></i>
2987 <span>To use instruct formatting, switch to OpenRouter under Text Completion API.</span>2987 <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>
2988 </small>2988 </small>
2989 </form>2989 </form>
2990 <form id="scale_form" data-source="scale" action="javascript:void(null);" method="post" enctype="multipart/form-data">2990 <form id="scale_form" data-source="scale" action="javascript:void(null);" method="post" enctype="multipart/form-data">
@@ -3319,7 +3319,7 @@
3319 </div>3319 </div>
3320 <h4 data-i18n="Enter a Model ID">Enter a Model ID</h4>3320 <h4 data-i18n="Enter a Model ID">Enter a Model ID</h4>
3321 <div class="flex-container">3321 <div class="flex-container">
3322 <input list="model_custom_select_fill" id="custom_model_id" class="text_pole wide100p" value="" autocomplete="off" data-i18n="[placeholder]Example: gpt-3.5-turbo" placeholder="Example: gpt-3.5-turbo">3322 <input list="model_custom_select_fill" id="custom_model_id" class="text_pole wide100p" value="" autocomplete="off" data-i18n="[placeholder]Example: gpt-4o" placeholder="Example: gpt-4o">
3323 <datalist id="model_custom_select_fill" class="text_pole model_custom_select"></datalist>3323 <datalist id="model_custom_select_fill" class="text_pole model_custom_select"></datalist>
3324 </div>3324 </div>
3325 <h4 data-i18n="Available Models">Available Models</h4>3325 <h4 data-i18n="Available Models">Available Models</h4>
@@ -4601,7 +4601,7 @@
4601 </div>4601 </div>
4602 </div>4602 </div>
4603 <div nane="AutoContiueBlock" class="inline-drawer wide100p flexFlowColumn">4603 <div nane="AutoContiueBlock" class="inline-drawer wide100p flexFlowColumn">
4604 <div class="inline-drawer-toggle inline-drawer-header userSettingsInnerExpandable" title="Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.">4604 <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.">
4605 <b><span data-i18n="Auto-Continue">Auto-Continue</span></b>4605 <b><span data-i18n="Auto-Continue">Auto-Continue</span></b>
4606 <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>4606 <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
4607 </div>4607 </div>
@@ -5734,7 +5734,7 @@
5734 <span class="drag-handle">&#9776;</span>5734 <span class="drag-handle">&#9776;</span>
5735 <div class="gap5px world_entry_thin_controls wide100p alignitemscenter">5735 <div class="gap5px world_entry_thin_controls wide100p alignitemscenter">
5736 <div class="inline-drawer-toggle fa-fw fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>5736 <div class="inline-drawer-toggle fa-fw fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
5737 <div class="fa-solid fa-toggle-on killSwitch" name="entryKillSwitch" title="Toggle entry's active state."></div>5737 <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>
5738 <div class="flex-container alignitemscenter wide100p">5738 <div class="flex-container alignitemscenter wide100p">
5739 <div class="WIEntryTitleAndStatus flex-container flex1 alignitemscenter">5739 <div class="WIEntryTitleAndStatus flex-container flex1 alignitemscenter">
5740 <div class="flex-container flex1">5740 <div class="flex-container flex1">
@@ -5967,7 +5967,7 @@
5967 </small>5967 </small>
5968 </div>5968 </div>
5969 <div class="range-block-range">5969 <div class="range-block-range">
5970 <input class="text_pole margin0" name="sticky" type="number" placeholder="Non-sticky" min="0" max="999999">5970 <input class="text_pole margin0" name="sticky" type="number" data-i18n="[placeholder]Non-sticky" placeholder="Non-sticky" min="0" max="999999">
5971 </div>5971 </div>
5972 </div>5972 </div>
5973 <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.">5973 <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 @@
5980 </small>5980 </small>
5981 </div>5981 </div>
5982 <div class="range-block-range">5982 <div class="range-block-range">
5983 <input class="text_pole margin0" name="cooldown" type="number" placeholder="No cooldown" min="0" max="999999">5983 <input class="text_pole margin0" name="cooldown" type="number" data-i18n="[placeholder]No cooldown" placeholder="No cooldown" min="0" max="999999">
5984 </div>5984 </div>
5985 </div>5985 </div>
5986 <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.">5986 <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 @@
5993 </small>5993 </small>
5994 </div>5994 </div>
5995 <div class="range-block-range">5995 <div class="range-block-range">
5996 <input class="text_pole margin0" name="delay" type="number" placeholder="No delay" min="0" max="999999">5996 <input class="text_pole margin0" name="delay" type="number" data-i18n="[placeholder]No delay" placeholder="No delay" min="0" max="999999">
5997 </div>5997 </div>
5998 </div>5998 </div>
5999 </div>5999 </div>
public/locales/ar-sa.json+1 -1
@@ -879,7 +879,7 @@
879 "popup-button-no": "لا",879 "popup-button-no": "لا",
880 "popup-button-cancel": "يلغي",880 "popup-button-cancel": "يلغي",
881 "popup-button-import": "يستورد",881 "popup-button-import": "يستورد",
882 "Advanced Defininitions": "تعريفات متقدمة",882 "Advanced Definitions": "تعريفات متقدمة",
883 "Prompt Overrides": "التجاوزات السريعة",883 "Prompt Overrides": "التجاوزات السريعة",
884 "(For Chat Completion and Instruct Mode)": "(لاستكمال الدردشة ووضع التعليمات)",884 "(For Chat Completion and Instruct Mode)": "(لاستكمال الدردشة ووضع التعليمات)",
885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "أدخل {{original}} في أي مربع لتضمين التعليمات الافتراضية المعنية من إعدادات النظام.",885 "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 @@
879 "popup-button-no": "NEIN",879 "popup-button-no": "NEIN",
880 "popup-button-cancel": "Stornieren",880 "popup-button-cancel": "Stornieren",
881 "popup-button-import": "Importieren",881 "popup-button-import": "Importieren",
882 "Advanced Defininitions": "Erweiterte Definitionen",882 "Advanced Definitions": "Erweiterte Definitionen",
883 "Prompt Overrides": "Eingabeaufforderungsüberschreibungen",883 "Prompt Overrides": "Eingabeaufforderungsüberschreibungen",
884 "(For Chat Completion and Instruct Mode)": "(Für Chat-Abschluss und Anweisungsmodus)",884 "(For Chat Completion and Instruct Mode)": "(Für Chat-Abschluss und Anweisungsmodus)",
885 "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.",885 "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 @@
879 "popup-button-no": "No",879 "popup-button-no": "No",
880 "popup-button-cancel": "Cancelar",880 "popup-button-cancel": "Cancelar",
881 "popup-button-import": "Importar",881 "popup-button-import": "Importar",
882 "Advanced Defininitions": "Definiciones avanzadas",882 "Advanced Definitions": "Definiciones avanzadas",
883 "Prompt Overrides": "Anulaciones rápidas",883 "Prompt Overrides": "Anulaciones rápidas",
884 "(For Chat Completion and Instruct Mode)": "(Para completar el chat y el modo de instrucción)",884 "(For Chat Completion and Instruct Mode)": "(Para completar el chat y el modo de instrucción)",
885 "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.",885 "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 @@
1439 "Still have questions?": "¿Todavía tienes preguntas?",1439 "Still have questions?": "¿Todavía tienes preguntas?",
1440 "Join the SillyTavern Discord": "Únete al Discord de SillyTavern",1440 "Join the SillyTavern Discord": "Únete al Discord de SillyTavern",
1441 "Post a GitHub issue": "Publicar un problema en GitHub",1441 "Post a GitHub issue": "Publicar un problema en GitHub",
1442 "Contact the developers": "Contactar a los desarrolladores"1442 "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"
1443}1550}
public/locales/fr-fr.json+7 -6
@@ -823,11 +823,13 @@
823 "popup-button-no": "Non",823 "popup-button-no": "Non",
824 "popup-button-cancel": "Annuler",824 "popup-button-cancel": "Annuler",
825 "popup-button-import": "Importer",825 "popup-button-import": "Importer",
826 "Prompt Overrides": "Remplacements de prompt",826 "Advanced Definitions": "Définitions avancé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)",
831 "Creator's Metadata (Not sent with the AI prompt)": "Métadonnées du créateur (Non envoyées avec l'instruction de l'IA)",833 "Creator's Metadata (Not sent with the AI prompt)": "Métadonnées du créateur (Non envoyées avec l'instruction de l'IA)",
832 "Creator's Metadata": "Métadonnées du créateur",834 "Creator's Metadata": "Métadonnées du créateur",
833 "(Not sent with the AI Prompt)": "(Non envoyé avec le prompt IA)",835 "(Not sent with the AI Prompt)": "(Non envoyé avec le prompt IA)",
@@ -2041,7 +2043,6 @@
2041 "Strategy": "Stratégie",2043 "Strategy": "Stratégie",
2042 "Position": "Position",2044 "Position": "Position",
2043 "Trigger %": "Déclencheur %",2045 "Trigger %": "Déclencheur %",
2044 "Advanced Definitions": "- Définitions\n Avancé",
2045 "Only chunk on custom boundary": "Only chunk on custom boundary",2046 "Only chunk on custom boundary": "Only chunk on custom boundary",
2046 "Generate Caption": "Générer une légende",2047 "Generate Caption": "Générer une légende",
2047 "Use System Prompt": "Utiliser le prompt système:",2048 "Use System Prompt": "Utiliser le prompt système:",
public/locales/is-is.json+1 -1
@@ -879,7 +879,7 @@
879 "popup-button-no": "Nei",879 "popup-button-no": "Nei",
880 "popup-button-cancel": "Hætta við",880 "popup-button-cancel": "Hætta við",
881 "popup-button-import": "Flytja inn",881 "popup-button-import": "Flytja inn",
882 "Advanced Defininitions": "Ítarleg skilgreiningar",882 "Advanced Definitions": "Ítarleg skilgreiningar",
883 "Prompt Overrides": "Hnekkja hvetjandi",883 "Prompt Overrides": "Hnekkja hvetjandi",
884 "(For Chat Completion and Instruct Mode)": "(Til að ljúka spjalli og leiðbeiningarham)",884 "(For Chat Completion and Instruct Mode)": "(Til að ljúka spjalli og leiðbeiningarham)",
885 "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.",885 "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 @@
879 "popup-button-no": "NO",879 "popup-button-no": "NO",
880 "popup-button-cancel": "Annulla",880 "popup-button-cancel": "Annulla",
881 "popup-button-import": "Importare",881 "popup-button-import": "Importare",
882 "Advanced Defininitions": "Definizioni avanzate",882 "Advanced Definitions": "Definizioni avanzate",
883 "Prompt Overrides": "Sostituzioni richieste",883 "Prompt Overrides": "Sostituzioni richieste",
884 "(For Chat Completion and Instruct Mode)": "(Per il completamento della chat e la modalità istruzione)",884 "(For Chat Completion and Instruct Mode)": "(Per il completamento della chat e la modalità istruzione)",
885 "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.",885 "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 @@
879 "popup-button-no": "いいえ",879 "popup-button-no": "いいえ",
880 "popup-button-cancel": "キャンセル",880 "popup-button-cancel": "キャンセル",
881 "popup-button-import": "インポート",881 "popup-button-import": "インポート",
882 "Advanced Defininitions": "高度な定義",882 "Advanced Definitions": "高度な定義",
883 "Prompt Overrides": "プロンプトのオーバーライド",883 "Prompt Overrides": "プロンプトのオーバーライド",
884 "(For Chat Completion and Instruct Mode)": "(チャット補完と指示モード用)",884 "(For Chat Completion and Instruct Mode)": "(チャット補完と指示モード用)",
885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "システム設定からの対応するデフォルトのプロンプトを含めるには、どちらかのボックスに{{original}}を挿入します。",885 "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 @@
895 "popup-button-no": "아니요",895 "popup-button-no": "아니요",
896 "popup-button-cancel": "취소",896 "popup-button-cancel": "취소",
897 "popup-button-import": "불러오기",897 "popup-button-import": "불러오기",
898 "Advanced Defininitions": "고급 정의",898 "Advanced Definitions": "고급 정의",
899 "Prompt Overrides": "프롬프트 무시",899 "Prompt Overrides": "프롬프트 무시",
900 "(For Chat Completion and Instruct Mode)": "(채팅 완료 및 지시 모드의 경우)",900 "(For Chat Completion and Instruct Mode)": "(채팅 완료 및 지시 모드의 경우)",
901 "Insert {{original}} into either box to include the respective default prompt from system settings.": "{{original}}를 해당 상자에 넣어 시스템 설정의 기본 프롬프트를 포함합니다.",901 "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 @@
879 "popup-button-no": "Nee",879 "popup-button-no": "Nee",
880 "popup-button-cancel": "Annuleren",880 "popup-button-cancel": "Annuleren",
881 "popup-button-import": "Importeren",881 "popup-button-import": "Importeren",
882 "Advanced Defininitions": "Geavanceerde definities",882 "Advanced Definitions": "Geavanceerde definities",
883 "Prompt Overrides": "Prompt-overschrijvingen",883 "Prompt Overrides": "Prompt-overschrijvingen",
884 "(For Chat Completion and Instruct Mode)": "(Voor voltooiing van chat en instructiemodus)",884 "(For Chat Completion and Instruct Mode)": "(Voor voltooiing van chat en instructiemodus)",
885 "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.",885 "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 @@
879 "popup-button-no": "Não",879 "popup-button-no": "Não",
880 "popup-button-cancel": "Cancelar",880 "popup-button-cancel": "Cancelar",
881 "popup-button-import": "Importar",881 "popup-button-import": "Importar",
882 "Advanced Defininitions": "Definições Avançadas",882 "Advanced Definitions": "Definições Avançadas",
883 "Prompt Overrides": "Substituições de prompt",883 "Prompt Overrides": "Substituições de prompt",
884 "(For Chat Completion and Instruct Mode)": "(Para conclusão de bate-papo e modo de instrução)",884 "(For Chat Completion and Instruct Mode)": "(Para conclusão de bate-papo e modo de instrução)",
885 "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.",885 "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 @@
265 "Current Members": "Текущие участники",265 "Current Members": "Текущие участники",
266 "Delete": "Удалить",266 "Delete": "Удалить",
267 "Cancel": "Отменить",267 "Cancel": "Отменить",
268 "Advanced Defininitions": "Расширенное описание",268 "Advanced Definitions": "Расширенное описание",
269 "Personality summary": "Резюме по личности",269 "Personality summary": "Резюме по личности",
270 "Scenario": "Сценарий",270 "Scenario": "Сценарий",
271 "Talkativeness": "Разговорчивость",271 "Talkativeness": "Разговорчивость",
@@ -294,7 +294,7 @@
294 "Avoid sending sensitive information to the Horde.": "Избегайте отправки личной информации Horde",294 "Avoid sending sensitive information to the Horde.": "Избегайте отправки личной информации Horde",
295 "Review the Privacy statement": "Ознакомиться с заявлением о конфиденциальности",295 "Review the Privacy statement": "Ознакомиться с заявлением о конфиденциальности",
296 "Trusted workers only": "Только доверенные рабочие машины",296 "Trusted workers only": "Только доверенные рабочие машины",
297 "For privacy reasons, your API key will be hidden after you reload the page.": "По причинам безопасности ваш API-ключ будет скрыт после перезагрузки страницы.",297 "For privacy reasons, your API key will be hidden after you reload the page.": "Из соображений безопасности ваш API-ключ будет скрыт после перезагрузки страницы.",
298 "-- Horde models not loaded --": "--Модель Horde не загружена--",298 "-- Horde models not loaded --": "--Модель Horde не загружена--",
299 "Example: http://127.0.0.1:5000/api ": "Пример: http://127.0.0.1:5000/api",299 "Example: http://127.0.0.1:5000/api ": "Пример: http://127.0.0.1:5000/api",
300 "No connection...": "Нет соединения...",300 "No connection...": "Нет соединения...",
@@ -331,7 +331,6 @@
331 "UID ↘": "UID ↘",331 "UID ↘": "UID ↘",
332 "Trigger% ↗": "Триггер% ↗",332 "Trigger% ↗": "Триггер% ↗",
333 "Trigger% ↘": "Триггер% ↘",333 "Trigger% ↘": "Триггер% ↘",
334 "Order:": "Порядок:",
335 "Depth:": "Глубина:",334 "Depth:": "Глубина:",
336 "Character Lore First": "Сначала лор персонажа",335 "Character Lore First": "Сначала лор персонажа",
337 "Global Lore First": "Сначала глобальный лор",336 "Global Lore First": "Сначала глобальный лор",
@@ -347,7 +346,7 @@
347 "After Char Defs": "↓Перс.",346 "After Char Defs": "↓Перс.",
348 "Before AN": "↑АЗ",347 "Before AN": "↑АЗ",
349 "After AN": "↓АЗ",348 "After AN": "↓АЗ",
350 "Order": "Порядок:",349 "Order": "Очерёдность:",
351 "Update a theme file": "Обновить файл темы",350 "Update a theme file": "Обновить файл темы",
352 "Save as a new theme": "Сохранить как новую тему",351 "Save as a new theme": "Сохранить как новую тему",
353 "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.",352 "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.",
@@ -497,7 +496,7 @@
497 "What this keyword should mean to the AI, sent verbatim": "Что это ключевое слово должно означать для ИИ, отправляется дословно",496 "What this keyword should mean to the AI, sent verbatim": "Что это ключевое слово должно означать для ИИ, отправляется дословно",
498 "Filter to Character(s)": "Фильтр по персонажу(ам)",497 "Filter to Character(s)": "Фильтр по персонажу(ам)",
499 "Character Exclusion": "Исключить персонажей",498 "Character Exclusion": "Исключить персонажей",
500 "Inclusion Group": "Включить персонажей",499 "Inclusion Group": "Группа записей",
501 "Only one entry with the same label will be activated": "Будет активна только одна запись с одинаковой меткой",500 "Only one entry with the same label will be activated": "Будет активна только одна запись с одинаковой меткой",
502 "-- Characters not found --": "-- Персонажей не найдено --",501 "-- Characters not found --": "-- Персонажей не найдено --",
503 "(This will be the first message from the character that starts every chat)": "(Это будет первое сообщение от персонажа, когда вы начинаете новый чат)",502 "(This will be the first message from the character that starts every chat)": "(Это будет первое сообщение от персонажа, когда вы начинаете новый чат)",
@@ -541,7 +540,7 @@
541 "NOT ANY": "НЕ ЛЮБОЙ",540 "NOT ANY": "НЕ ЛЮБОЙ",
542 "Optional Filter": "Дополнительный фильтр",541 "Optional Filter": "Дополнительный фильтр",
543 "New Entry": "Новая запись",542 "New Entry": "Новая запись",
544 "Fill empty Memo/Titles with Keywords": "Заполните пустые Заметки/Названия ключевыми словами",543 "Fill empty Memo/Titles with Keywords": "Заполнить пустые названия ключевыми словами",
545 "AI Response Formatting": "Формат ответа ИИ",544 "AI Response Formatting": "Формат ответа ИИ",
546 "Change Background Image": "Изменить фон",545 "Change Background Image": "Изменить фон",
547 "Extensions": "Расширения",546 "Extensions": "Расширения",
@@ -628,7 +627,7 @@
628 "UI Theme": "Тема UI",627 "UI Theme": "Тема UI",
629 "This message is invisible for the AI": "Это сообщение невидимо для ИИ",628 "This message is invisible for the AI": "Это сообщение невидимо для ИИ",
630 "Sampler Priority": "Приоритет сэмплеров",629 "Sampler Priority": "Приоритет сэмплеров",
631 "Ooba only. Determines the order of samplers.": "Только Ooba. Определяет порядок сэмплеров.",630 "Ooba only. Determines the order of samplers.": "Только oobabooga. Определяет порядок сэмплеров.",
632 "Load default order": "Загрузить стандартный порядок",631 "Load default order": "Загрузить стандартный порядок",
633 "Max Tokens Second": "Макс. кол-во токенов в секунду",632 "Max Tokens Second": "Макс. кол-во токенов в секунду",
634 "CFG": "CFG",633 "CFG": "CFG",
@@ -1132,7 +1131,7 @@
1132 "Custom API Key": "Ключ от кастомного API",1131 "Custom API Key": "Ключ от кастомного API",
1133 "(Optional)": "(необязательно)",1132 "(Optional)": "(необязательно)",
1134 "Enter a Model ID": "Введите идентификатор модели",1133 "Enter a Model ID": "Введите идентификатор модели",
1135 "Example: gpt-3.5-turbo": "Пример: gpt-3.5-turbo",1134 "Example: gpt-4o": "Пример: gpt-4o",
1136 "Available Models": "Доступные модели",1135 "Available Models": "Доступные модели",
1137 "Prompt Post-Processing": "Постобработка промпта",1136 "Prompt Post-Processing": "Постобработка промпта",
1138 "Applies additional processing to the prompt before sending it to the API.": "Позволяет обработать промпт перед отправкой в API.",1137 "Applies additional processing to the prompt before sending it to the API.": "Позволяет обработать промпт перед отправкой в API.",
@@ -1342,7 +1341,7 @@
1342 "Chat Lorebook": "Chat Lorebook for",1341 "Chat Lorebook": "Chat Lorebook for",
1343 "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.",1342 "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.",
1344 "Use tag as folder": "Tag as folder",1343 "Use tag as folder": "Tag as folder",
1345 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "Статус записи:\n 🔵 Постоянная\n 🟢 Обычная\n 🔗 Векторизованная\n ❌ Отключена",1344 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "Статус записи:\n 🔵 Постоянная\n 🟢 Обычная\n 🔗 Векторизованная",
1346 "WI_Entry_Status_Constant": "Постоянная",1345 "WI_Entry_Status_Constant": "Постоянная",
1347 "WI_Entry_Status_Normal": "Обычная",1346 "WI_Entry_Status_Normal": "Обычная",
1348 "WI_Entry_Status_Vectorized": "Векторизованная",1347 "WI_Entry_Status_Vectorized": "Векторизованная",
@@ -1366,13 +1365,7 @@
1366 "Can be used to automatically activate Quick Replies": "Can be used to automatically activate Quick Replies",1365 "Can be used to automatically activate Quick Replies": "Can be used to automatically activate Quick Replies",
1367 "Automation ID": "Automation ID",1366 "Automation ID": "Automation ID",
1368 "( None )": "( None )",1367 "( 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",
1374 "Add Memo": "Add Memo",1368 "Add Memo": "Add Memo",
1375 "close": "close",
1376 "reset": "reset",1369 "reset": "reset",
1377 "save": "save",1370 "save": "save",
1378 "Open checkpoint chat": "Открыть чат из чекпоинта",1371 "Open checkpoint chat": "Открыть чат из чекпоинта",
@@ -2035,5 +2028,121 @@
2035 "tags_sorting_desc": "Автоматически сортировать теги по алфавиту после создания или переименования одного из них.\nПри выключении новые теги будут просто добавляться в конец.\n\nЕсли вручную перетащить один из тегов на другое место, автосортировка отключится.",2028 "tags_sorting_desc": "Автоматически сортировать теги по алфавиту после создания или переименования одного из них.\nПри выключении новые теги будут просто добавляться в конец.\n\nЕсли вручную перетащить один из тегов на другое место, автосортировка отключится.",
2036 "Imported tags:": "Импортируемые теги:",2029 "Imported tags:": "Импортируемые теги:",
2037 "Importing Tags": "Импорт тегов",2030 "Importing Tags": "Импорт тегов",
2038 "Couldn't import tags:": "Не удалось импортировать теги:"2031 "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": "Закрыть"
2039}2148}
public/locales/uk-ua.json+1 -1
@@ -879,7 +879,7 @@
879 "popup-button-no": "Немає",879 "popup-button-no": "Немає",
880 "popup-button-cancel": "Скасувати",880 "popup-button-cancel": "Скасувати",
881 "popup-button-import": "Імпорт",881 "popup-button-import": "Імпорт",
882 "Advanced Defininitions": "Розширені визначення",882 "Advanced Definitions": "Розширені визначення",
883 "Prompt Overrides": "Перевизначення підказок",883 "Prompt Overrides": "Перевизначення підказок",
884 "(For Chat Completion and Instruct Mode)": "(Для завершення чату та режиму інструктажу)",884 "(For Chat Completion and Instruct Mode)": "(Для завершення чату та режиму інструктажу)",
885 "Insert {{original}} into either box to include the respective default prompt from system settings.": "Вставте {{original}} в будь-яке поле, щоб включити відповідний запит з налаштувань системи.",885 "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 @@
879 "popup-button-no": "KHÔNG",879 "popup-button-no": "KHÔNG",
880 "popup-button-cancel": "Hủy",880 "popup-button-cancel": "Hủy",
881 "popup-button-import": "Nhập",881 "popup-button-import": "Nhập",
882 "Advanced Defininitions": "Các Định nghĩa Nâng cao",882 "Advanced Definitions": "Các Định nghĩa Nâng cao",
883 "Prompt Overrides": "Ghi đè Prompt",883 "Prompt Overrides": "Ghi đè Prompt",
884 "(For Chat Completion and Instruct Mode)": "(Đối với chế độ hoàn thành trò chuyện và hướng dẫn)",884 "(For Chat Completion and Instruct Mode)": "(Đối với chế độ hoàn thành trò chuyện và hướng dẫn)",
885 "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.",885 "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+102 -60
@@ -78,7 +78,7 @@
78 "Allow": "Allow",78 "Allow": "Allow",
79 "Forbid": "Forbid",79 "Forbid": "Forbid",
80 "Enable OpenAI completion streaming": "启用OpenAI文本补全流式传输",80 "Enable OpenAI completion streaming": "启用OpenAI文本补全流式传输",
81 "Display the response bit by bit as it is generated.": "随着回复的生成,逐位显示结果。",81 "Display the response bit by bit as it is generated.": "随着回复的生成,逐词逐句地显示结果。",
82 "When this is off, responses will be displayed all at once when they are complete.": "当此选项关闭时,回复将在完成后一次性显示。",82 "When this is off, responses will be displayed all at once when they are complete.": "当此选项关闭时,回复将在完成后一次性显示。",
83 "Frequency Penalty": "频率惩罚",83 "Frequency Penalty": "频率惩罚",
84 "Presence Penalty": "存在惩罚",84 "Presence Penalty": "存在惩罚",
@@ -185,13 +185,13 @@
185 "Mirostat Eta": "Mirostat η",185 "Mirostat Eta": "Mirostat η",
186 "Learning rate of Mirostat": "Mirostat 的学习率。",186 "Learning rate of Mirostat": "Mirostat 的学习率。",
187 "Beam search": "束搜索",187 "Beam search": "束搜索",
188 "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.",188 "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采样中使用的贪婪暴力算法,用于找到最可能的单词或标记序列。它一次扩展多个候选序列,在每一步保留固定数量(光束宽度)的最佳序列。",
189 "# of Beams": "# of Beams",189 "# of Beams": "光束数量",
190 "The number of sequences generated at each step with Beam Search.": "The number of sequences generated at each step with Beam Search.",190 "The number of sequences generated at each step with Beam Search.": "The number of sequences generated at each step with Beam Search.",
191 "Length Penalty": "长度惩罚",191 "Length Penalty": "长度惩罚",
192 "Penalize sequences based on their length.": "Penalize sequences based on their length.",192 "Penalize sequences based on their length.": "Penalize sequences based on their length.",
193 "Early Stopping": "提前停止",193 "Early Stopping": "提前停止",
194 "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.",194 "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.": "控制光束搜索的停止条件。勾选时,当生成到达‘光束数量’的序列时停止。如果未勾选,则采用启发式方法,当几乎不可能找到更好的候选项时停止生成。",
195 "Contrastive search": "对比搜索",195 "Contrastive search": "对比搜索",
196 "Contrastive_search_txt": "通过利用大多数 LLM 表示空间的各向同性以鼓励多样性同时保持一致性的采样器。详见 Su 等人在 2022 年发表的论文 《A Contrastive Framework for Neural Text Generation》。",196 "Contrastive_search_txt": "通过利用大多数 LLM 表示空间的各向同性以鼓励多样性同时保持一致性的采样器。详见 Su 等人在 2022 年发表的论文 《A Contrastive Framework for Neural Text Generation》。",
197 "Penalty Alpha": "惩罚系数 α",197 "Penalty Alpha": "惩罚系数 α",
@@ -208,7 +208,7 @@
208 "Speculative Ngram": "推测性 Ngram",208 "Speculative Ngram": "推测性 Ngram",
209 "Use a different speculative decoding method without a draft model": "使用不同的推测解码方法(不采用草稿模型)。最好使用草稿模型。推测性 Ngram 的效果不太好。",209 "Use a different speculative decoding method without a draft model": "使用不同的推测解码方法(不采用草稿模型)。最好使用草稿模型。推测性 Ngram 的效果不太好。",
210 "Spaces Between Special Tokens": "特殊词符之间的空格",210 "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 时会使用随机种子。",
212 "LLaMA / Mistral / Yi models only": "LLaMA / Mistral / Yi模型专用。首先确保您选择了适当的词符化器。\n这项设置决定了你不想在结果中看到的字符串。\n每行一个字符串。可以是文本或者[词符id]。\n许多词符以空格开头。如果不确定,请使用词符计数器。",212 "LLaMA / Mistral / Yi models only": "LLaMA / Mistral / Yi模型专用。首先确保您选择了适当的词符化器。\n这项设置决定了你不想在结果中看到的字符串。\n每行一个字符串。可以是文本或者[词符id]。\n许多词符以空格开头。如果不确定,请使用词符计数器。",
213 "Example: some text [42, 69, 1337]": "例如:\n一些文本\n[42, 69, 1337]",213 "Example: some text [42, 69, 1337]": "例如:\n一些文本\n[42, 69, 1337]",
214 "CFG": "CFG",214 "CFG": "CFG",
@@ -227,8 +227,8 @@
227 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "仅限 llama.cpp。确定采样器的顺序。如果 Mirostat 模式不为 0,则忽略采样器顺序。",227 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "仅限 llama.cpp。确定采样器的顺序。如果 Mirostat 模式不为 0,则忽略采样器顺序。",
228 "Sampler Priority": "采样器优先级",228 "Sampler Priority": "采样器优先级",
229 "Ooba only. Determines the order of samplers.": "确定采样器的顺序(仅适用于Ooba)",229 "Ooba only. Determines the order of samplers.": "确定采样器的顺序(仅适用于Ooba)",
230 "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. Skew is always applied post-softmax, so it's not included here.",230 "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "仅适用于 Aphrodite,用于确定采样器的顺序。偏移(Skew)始终在 softmax 后应用,因此不包含在这里。",
231 "Aphrodite only. Determines the order of samplers.": "Aphrodite only. Determines the order of samplers.",231 "Aphrodite only. Determines the order of samplers.": "仅适用于 Aphrodite。用于确定采样器的顺序。",
232 "Character Names Behavior": "角色名称行为",232 "Character Names Behavior": "角色名称行为",
233 "Helps the model to associate messages with characters.": "有助于模型将消息与角色关联起来。",233 "Helps the model to associate messages with characters.": "有助于模型将消息与角色关联起来。",
234 "None": "无",234 "None": "无",
@@ -266,13 +266,15 @@
266 "Use system prompt": "使用系统提示词",266 "Use system prompt": "使用系统提示词",
267 "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过",267 "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过",
268 "Merges_all_system_messages_desc_2": "字段发送。",268 "Merges_all_system_messages_desc_2": "字段发送。",
269 "Show model thoughts": "展示思维链",
270 "Display the model's internal thoughts in the response.": "展示模型在回复时的内部思维链。",
269 "Assistant Prefill": "AI预填",271 "Assistant Prefill": "AI预填",
270 "Expand the editor": "展开编辑器",272 "Expand the editor": "展开编辑器",
271 "Start Claude's answer with...": "以如下内容开始Claude的回答...",273 "Start Claude's answer with...": "以如下内容开始Claude的回答...",
272 "Assistant Impersonation Prefill": "AI帮答预填",274 "Assistant Impersonation Prefill": "AI帮答预填",
273 "Use system prompt (Claude 2.1+ only)": "使用系统提示词(仅适用于Claude 2.1+)",275 "Use system prompt (Claude 2.1+ only)": "使用系统提示词(仅适用于Claude 2.1+)",
274 "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "为支持的模型发送系统提示词。如果禁用,则用户消息将添加到提示词的开头。",276 "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "为支持的模型发送系统提示词。如果禁用,则用户消息将添加到提示词的开头。",
275 "Confirm token parsing with": "Confirm token parsing with",277 "Confirm token parsing with": "确认使用以下工具进行词符解析",
276 "Tokenizer": "词符化器",278 "Tokenizer": "词符化器",
277 "New preset": "新预设",279 "New preset": "新预设",
278 "Delete preset": "删除预设",280 "Delete preset": "删除预设",
@@ -316,9 +318,9 @@
316 "Get your NovelAI API Key": "获取您的 NovelAI API 密钥",318 "Get your NovelAI API Key": "获取您的 NovelAI API 密钥",
317 "Enter it in the box below": "在下面的框中输入",319 "Enter it in the box below": "在下面的框中输入",
318 "Novel AI Model": "Novel AI 模型",320 "Novel AI Model": "Novel AI 模型",
319 "No connection...": "没有连接...",321 "No connection...": "无连接...",
320 "API Type": "API 类型",322 "API Type": "API 类型",
321 "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]",323 "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "通用(兼容 OpenAI)[LM Studio、LiteLLM 等]",
322 "TogetherAI API Key": "TogetherAI API 密钥",324 "TogetherAI API Key": "TogetherAI API 密钥",
323 "TogetherAI Model": "TogetherAI 模型",325 "TogetherAI Model": "TogetherAI 模型",
324 "-- Connect to the API --": "-- 连接到API --",326 "-- Connect to the API --": "-- 连接到API --",
@@ -350,7 +352,7 @@
350 "All": "All",352 "All": "All",
351 "class": "All Classes",353 "class": "All Classes",
352 "Toggle grid view": "切换网格视图",354 "Toggle grid view": "切换网格视图",
353 "No model description": "[No description]",355 "No model description": "[无描述]",
354 "vllm-project/vllm": "vllm-project/vllm(OpenAI API 包装器模式)",356 "vllm-project/vllm": "vllm-project/vllm(OpenAI API 包装器模式)",
355 "vLLM API key": "vLLM API 密钥",357 "vLLM API key": "vLLM API 密钥",
356 "Example: 127.0.0.1:8000": "示例:http://127.0.0.1:8000",358 "Example: 127.0.0.1:8000": "示例:http://127.0.0.1:8000",
@@ -404,7 +406,7 @@
404 "OpenAI Model": "OpenAI 模型",406 "OpenAI Model": "OpenAI 模型",
405 "Bypass API status check": "绕过API状态检查",407 "Bypass API status check": "绕过API状态检查",
406 "Show External models (provided by API)": "显示外部模型(由API提供)",408 "Show External models (provided by API)": "显示外部模型(由API提供)",
407 "Claude API Key": "Claude API Key",409 "Claude API Key": "Claude API 密钥",
408 "Get your key from": "从以下位置获取您的密钥",410 "Get your key from": "从以下位置获取您的密钥",
409 "Anthropic's developer console": "Anthropic 开发者控制台",411 "Anthropic's developer console": "Anthropic 开发者控制台",
410 "Claude Model": "Claude 模型",412 "Claude Model": "Claude 模型",
@@ -430,23 +432,28 @@
430 "Groq Model": "Groq 模型",432 "Groq Model": "Groq 模型",
431 "NanoGPT API Key": "NanoGPT API Key",433 "NanoGPT API Key": "NanoGPT API Key",
432 "NanoGPT Model": "NanoGPT Model",434 "NanoGPT Model": "NanoGPT Model",
435 "DeepSeek API Key": "DeepSeek API 密钥",
436 "DeepSeek Model": "DeepSeek 模型",
433 "Perplexity API Key": "Perplexity API 密钥",437 "Perplexity API Key": "Perplexity API 密钥",
434 "Perplexity Model": "Perplexity 模型",438 "Perplexity Model": "Perplexity 模型",
435 "Cohere API Key": "Cohere API 密钥",439 "Cohere API Key": "Cohere API 密钥",
436 "Cohere Model": "Cohere 模型",440 "Cohere Model": "Cohere 模型",
437 "Block Entropy API Key": "Block Entropy API Key",441 "Block Entropy API Key": "Block Entropy API 密钥",
438 "Select a Model": "Select a Model",442 "Select a Model": "选择一个模型",
439 "Custom Endpoint (Base URL)": "自定义端点(基本 URL)",443 "Custom Endpoint (Base URL)": "自定义端点(基础 URL)",
440 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",444 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",
441 "at the end of the URL!": "到 URL 的末尾!",445 "at the end of the URL!": "到 URL 的末尾!",
442 "Custom API Key": "自定义 API 密钥",446 "Custom API Key": "自定义 API 密钥",
443 "(Optional)": "(可选)",447 "(Optional)": "(可选)",
444 "Enter a Model ID": "输入模型名",448 "Enter a Model ID": "输入模型名",
445 "Example: gpt-3.5-turbo": "例如:gpt-3.5-turbo",449 "Example: gpt-4o": "例如:gpt-4o",
446 "Available Models": "可用模型",450 "Available Models": "可用模型",
447 "Prompt Post-Processing": "提示词后处理",451 "Prompt Post-Processing": "提示词后处理",
448 "Applies additional processing to the prompt before sending it to the API.": "在将提示词发送到 API 之前对其进行额外处理。",452 "Applies additional processing to the prompt before sending it to the API.": "在将提示词发送到 API 之前对其进行额外处理。",
449 "prompt_post_processing_none": "未选择",453 "prompt_post_processing_none": "未选择",
454 "prompt_post_processing_merge": "合并相同角色连续的发言",
455 "prompt_post_processing_semi": "半严格(强制对话角色交替)",
456 "prompt_post_processing_strict": "严格(强制对话角色交替、用户最先)",
450 "01.AI API Key": "01.AI API密钥",457 "01.AI API Key": "01.AI API密钥",
451 "01.AI Model": "01.AI 模型",458 "01.AI Model": "01.AI 模型",
452 "Additional Parameters": "附加参数",459 "Additional Parameters": "附加参数",
@@ -503,25 +510,25 @@
503 "Never": "永不",510 "Never": "永不",
504 "Groups and Past Personas": "Groups and Past Personas",511 "Groups and Past Personas": "Groups and Past Personas",
505 "Always": "永远",512 "Always": "永远",
506 "Instruct Sequences": "Instruct Sequences",513 "Instruct Sequences": "指令序列",
507 "User Message Sequences": "User Message Sequences",514 "User Message Sequences": "用户消息序列",
508 "Inserted before a User message and as a last prompt line when impersonating.": "插入到用户消息之前并作为模拟时的最后一行提示词。",515 "Inserted before a User message and as a last prompt line when impersonating.": "插入到用户消息之前并作为模拟时的最后一行提示词。",
509 "User Prefix": "用户消息前缀",516 "User Prefix": "用户消息前缀",
510 "Inserted after a User message.": "插入到用户消息之后。",517 "Inserted after a User message.": "插入到用户消息之后。",
511 "User Suffix": "用户消息后缀",518 "User Suffix": "用户消息后缀",
512 "Assistant Message Sequences": "Assistant Message Sequences",519 "Assistant Message Sequences": "助手消息序列",
513 "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "插入到助手消息之前并作为生成 AI 回复时的最后一行提示词。",520 "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "插入到助手消息之前并作为生成 AI 回复时的最后一行提示词。",
514 "Assistant Prefix": "助手消息前缀",521 "Assistant Prefix": "助手消息前缀",
515 "Inserted after an Assistant message.": "插入于助手消息之后。",522 "Inserted after an Assistant message.": "插入于助手消息之后。",
516 "Assistant Suffix": "助手消息后缀",523 "Assistant Suffix": "助手消息后缀",
517 "System Message Sequences": "System Message Sequences",524 "System Message Sequences": "系统消息序列",
518 "Inserted before a System (added by slash commands or extensions) message.": "插入到系统(由快捷命令或扩展添加)消息之前。",525 "Inserted before a System (added by slash commands or extensions) message.": "插入到系统(由快捷命令或扩展添加)消息之前。",
519 "System Prefix": "System Message Prefix",526 "System Prefix": "系统消息前缀",
520 "Inserted after a System message.": "插入到系统消息之后。",527 "Inserted after a System message.": "插入到系统消息之后。",
521 "System Suffix": "System Message Suffix",528 "System Suffix": "系统消息后缀",
522 "If enabled, System Sequences will be the same as User Sequences.": "如果启用,系统序列将与用户序列相同。",529 "If enabled, System Sequences will be the same as User Sequences.": "如果启用,系统序列将与用户序列相同。",
523 "System same as User": "系统与用户相同",530 "System same as User": "系统与用户相同",
524 "System Prompt Sequences": "System Prompt Sequences",531 "System Prompt Sequences": "系统提示词序列",
525 "Inserted before a System prompt.": "插入到系统提示词之前。",532 "Inserted before a System prompt.": "插入到系统提示词之前。",
526 "System Prompt Prefix": "系统提示词前缀",533 "System Prompt Prefix": "系统提示词前缀",
527 "Inserted after a System prompt.": "在系统提示词后插入。",534 "Inserted after a System prompt.": "在系统提示词后插入。",
@@ -556,7 +563,7 @@
556 "Token Padding": "词符填充",563 "Token Padding": "词符填充",
557 "Miscellaneous": "杂项",564 "Miscellaneous": "杂项",
558 "Non-markdown strings": "非 Markdown 字符串",565 "Non-markdown strings": "非 Markdown 字符串",
559 "comma delimited,no spaces between": "comma delimited,no spaces between",566 "comma delimited,no spaces between": "以逗号分隔,无需空格",
560 "Start Reply With": "以...开始回复",567 "Start Reply With": "以...开始回复",
561 "Show reply prefix in chat": "在聊天中显示回复前缀",568 "Show reply prefix in chat": "在聊天中显示回复前缀",
562 "World Info": "世界信息",569 "World Info": "世界信息",
@@ -688,8 +695,8 @@
688 "Show Message Token Count": "显示消息词符数",695 "Show Message Token Count": "显示消息词符数",
689 "Single-row message input area. Mobile only, no effect on PC": "将输入框限制为一行。仅适用于移动设备,对PC无影响",696 "Single-row message input area. Mobile only, no effect on PC": "将输入框限制为一行。仅适用于移动设备,对PC无影响",
690 "Compact Input Area (Mobile)": "紧凑输入区域(移动端)",697 "Compact Input Area (Mobile)": "紧凑输入区域(移动端)",
691 "Display swipe numbers for all messages, not just the last.": "Display swipe numbers for all messages, not just the last.",698 "Display swipe numbers for all messages, not just the last.": "显示所有信息的滑动编号,而非仅限最后一条。",
692 "Swipe # for All Messages": "Swipe # for All Messages",699 "Swipe # for All Messages": "给所有信息分配滑动编号 #",
693 "In the Character Management panel, show quick selection buttons for favorited characters": "在角色管理面板中,显示快速选择按钮以选择收藏的角色",700 "In the Character Management panel, show quick selection buttons for favorited characters": "在角色管理面板中,显示快速选择按钮以选择收藏的角色",
694 "Characters Hotswap": "角色卡热切换",701 "Characters Hotswap": "角色卡热切换",
695 "Enable magnification for zoomed avatar display.": "启用放大功能以放大头像显示。",702 "Enable magnification for zoomed avatar display.": "启用放大功能以放大头像显示。",
@@ -894,7 +901,7 @@
894 "Favorite characters to add them to HotSwaps": "收藏角色以将它们添加到快速热切换区",901 "Favorite characters to add them to HotSwaps": "收藏角色以将它们添加到快速热切换区",
895 "Token counts may be inaccurate and provided just for reference.": "词符计数可能不准确,仅供参考。",902 "Token counts may be inaccurate and provided just for reference.": "词符计数可能不准确,仅供参考。",
896 "Total tokens": "总词符数",903 "Total tokens": "总词符数",
897 "Calculating...": "正在计算…",904 "Calculating...": "正在计算...",
898 "Tokens": "词符数",905 "Tokens": "词符数",
899 "Permanent tokens": "永久词符",906 "Permanent tokens": "永久词符",
900 "Permanent": "恒定的",907 "Permanent": "恒定的",
@@ -936,10 +943,10 @@
936 "Chat Name (Optional)": "聊天名称(可选)",943 "Chat Name (Optional)": "聊天名称(可选)",
937 "Chat Lore": "聊天知识",944 "Chat Lore": "聊天知识",
938 "Click to select a new avatar for this group": "单击选择该群聊的新头像",945 "Click to select a new avatar for this group": "单击选择该群聊的新头像",
939 "Group reply strategy": "群聊回复策略",946 "Group reply strategy": "群聊发言顺序",
940 "Manual": "手动",947 "Manual": "手动",
941 "Natural order": "自然顺序",948 "Natural order": "自然顺序",
942 "List order": "上下顺序",949 "List order": "从上到下",
943 "Group generation handling mode": "群组生成处理模式",950 "Group generation handling mode": "群组生成处理模式",
944 "Swap character cards": "交换角色卡",951 "Swap character cards": "交换角色卡",
945 "Join character cards (exclude muted)": "加入角色卡(不包括被禁言的)",952 "Join character cards (exclude muted)": "加入角色卡(不包括被禁言的)",
@@ -990,7 +997,7 @@
990 "popup-button-import": "导入",997 "popup-button-import": "导入",
991 "popup-button-crop": "裁剪",998 "popup-button-crop": "裁剪",
992 "Close popup": "关闭弹出窗口",999 "Close popup": "关闭弹出窗口",
993 "Advanced Defininitions": "高级定义",1000 "Advanced Definitions": "高级定义",
994 "Prompt Overrides": "提示词覆盖",1001 "Prompt Overrides": "提示词覆盖",
995 "(For Chat Completion and Instruct Mode)": "(用于聊天补全和指导模式)",1002 "(For Chat Completion and Instruct Mode)": "(用于聊天补全和指导模式)",
996 "Insert {{original}} into either box to include the respective default prompt from system settings.": "将{{original}}插入到任一框中,以包含系统设置中的相应默认提示词。",1003 "Insert {{original}} into either box to include the respective default prompt from system settings.": "将{{original}}插入到任一框中,以包含系统设置中的相应默认提示词。",
@@ -1023,7 +1030,7 @@
1023 "Chatty": "高",1030 "Chatty": "高",
1024 "Examples of dialogue": "对话示例",1031 "Examples of dialogue": "对话示例",
1025 "Important to set the character's writing style.": "设置角色的写作风格,很重要!",1032 "Important to set the character's writing style.": "设置角色的写作风格,很重要!",
1026 "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天对话的示例,每个示例都另起一行以<START>开头。)",1033 "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天对话的示例,每个示例都另起一行以<START>开头。)",
1027 "Save": "保存",1034 "Save": "保存",
1028 "Chat History": "聊天记录",1035 "Chat History": "聊天记录",
1029 "Import Chat": "导入聊天",1036 "Import Chat": "导入聊天",
@@ -1107,12 +1114,15 @@
1107 "A relative likelihood of entry activation within the group": "组内进入激活的相对可能性",1114 "A relative likelihood of entry activation within the group": "组内进入激活的相对可能性",
1108 "Group Weight": "组权重",1115 "Group Weight": "组权重",
1109 "Sticky entries will stay active for N messages after being triggered.": "粘性条目在被触发后将保持活跃状态​​ N 条消息。",1116 "Sticky entries will stay active for N messages after being triggered.": "粘性条目在被触发后将保持活跃状态​​ N 条消息。",
1110 "Sticky": "粘性",1117 "Sticky": "黏性",
1118 "Non-sticky": "无黏性",
1111 "Entries with a cooldown can't be activated N messages after being triggered.": "具有冷却时间的条目在触发后 N 条消息内无法被激活。",1119 "Entries with a cooldown can't be activated N messages after being triggered.": "具有冷却时间的条目在触发后 N 条消息内无法被激活。",
1112 "Cooldown": "冷却",1120 "Cooldown": "冷却",
1121 "No cooldown": "无冷却",
1113 "Entries with a delay can't be activated until there are N messages present in the chat.": "直到聊天中出现 N 条消息时,延迟的条目才能被激活。",1122 "Entries with a delay can't be activated until there are N messages present in the chat.": "直到聊天中出现 N 条消息时,延迟的条目才能被激活。",
1114 "Delay": "延迟",1123 "Delay": "延迟",
1115 "Filter to Characters or Tags": "应用到角色或标签",1124 "No delay": "无延迟",
1125 "Filter to Characters or Tags": "绑定到角色或标签",
1116 "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "切换角色/标签筛选方式,将列出的角色和标签排除在匹配范围之外",1126 "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "切换角色/标签筛选方式,将列出的角色和标签排除在匹配范围之外",
1117 "Exclude": "排除",1127 "Exclude": "排除",
1118 "-- Characters not found --": "-- 未找到角色 --",1128 "-- Characters not found --": "-- 未找到角色 --",
@@ -1132,8 +1142,8 @@
1132 "prompt_manager_relative": "相对",1142 "prompt_manager_relative": "相对",
1133 "prompt_manager_in_chat": "聊天中",1143 "prompt_manager_in_chat": "聊天中",
1134 "prompt_manager_depth": "深度",1144 "prompt_manager_depth": "深度",
1135 "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。0 = 在最后一条消息之后,1 = 在最后一条消息之前,等等。",1145 "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。“0”为在最后一条消息之后,“1”为在最后一条消息之前,等等。",
1136 "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.",1146 "The content of this prompt is pulled from elsewhere and cannot be edited here.": "此提示词的内容是从其他地方提取的,无法在此处进行编辑。",
1137 "Prompt": "提示词",1147 "Prompt": "提示词",
1138 "The prompt to be sent.": "要发送的提示词。",1148 "The prompt to be sent.": "要发送的提示词。",
1139 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使选择覆盖,此提示词也不能被角色卡覆盖。",1149 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使选择覆盖,此提示词也不能被角色卡覆盖。",
@@ -1194,7 +1204,7 @@
1194 "alternate_greetings_hint_1": "点击",1204 "alternate_greetings_hint_1": "点击",
1195 "alternate_greetings_hint_2": "按钮即可开始!",1205 "alternate_greetings_hint_2": "按钮即可开始!",
1196 "Alternate Greeting #": "额外问候语 #",1206 "Alternate Greeting #": "额外问候语 #",
1197 "(This will be the first message from the character that starts every chat)": "(这是每次聊天开始时角色的第一条消息)",1207 "(This will be the first message from the character that starts every chat)": "(这是每次聊天开始时角色的第一条消息)",
1198 "View contents": "查看内容",1208 "View contents": "查看内容",
1199 "Remove the file": "删除文件",1209 "Remove the file": "删除文件",
1200 "Author's Note": "作者注释",1210 "Author's Note": "作者注释",
@@ -1207,7 +1217,7 @@
1207 "Insertion Frequency": "插入频率",1217 "Insertion Frequency": "插入频率",
1208 "(0 = Disable, 1 = Always)": "(“0”为禁用,“1”为始终)",1218 "(0 = Disable, 1 = Always)": "(“0”为禁用,“1”为始终)",
1209 "User inputs until next insertion:": "用户输入直到下一次插入:",1219 "User inputs until next insertion:": "用户输入直到下一次插入:",
1210 "Character Author's Note (Private)": "人物作者注(私有)",1220 "Character Author's Note (Private)": "人物作者注(私密)",
1211 "Won't be shared with the character card on export.": "导出时不会与角色卡共享。",1221 "Won't be shared with the character card on export.": "导出时不会与角色卡共享。",
1212 "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.": "会自动添加为该角色的作者注解,在群聊中使用,但群聊开启时无法修改。",1222 "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.": "会自动添加为该角色的作者注解,在群聊中使用,但群聊开启时无法修改。",
1213 "Use character author's note": "使用角色作者的注释",1223 "Use character author's note": "使用角色作者的注释",
@@ -1234,9 +1244,9 @@
1234 "Insertion Depth:": "插入深度:",1244 "Insertion Depth:": "插入深度:",
1235 "Token Probabilities": "词符概率",1245 "Token Probabilities": "词符概率",
1236 "Select a token to see alternatives considered by the AI.": "选择一个词符来查看 AI 考虑的替代方案。",1246 "Select a token to see alternatives considered by the AI.": "选择一个词符来查看 AI 考虑的替代方案。",
1237 "Reroll with the entire prefix": "Reroll with the entire prefix",1247 "Reroll with the entire prefix": "使用完整前缀重新生成",
1238 "Not connected to API!": "未连接到API!",1248 "Not connected to API!": "未连接到API!",
1239 "Type a message, or /? for help": "键入消息,或 /? 获取帮助",1249 "Type a message, or /? for help": "输入想发送的消息,或输入 /? 获取帮助",
1240 "Continue script execution": "继续执行脚本",1250 "Continue script execution": "继续执行脚本",
1241 "Pause script execution": "暂停执行脚本",1251 "Pause script execution": "暂停执行脚本",
1242 "Abort script execution": "中止执行脚本",1252 "Abort script execution": "中止执行脚本",
@@ -1355,7 +1365,7 @@
1355 "You are in offline mode. Click on the image below to set the expression.": "您处于离线模式。点击下方图片即可设置表情。",1365 "You are in offline mode. Click on the image below to set the expression.": "您处于离线模式。点击下方图片即可设置表情。",
1356 "Sprite Folder Override": "表情文件夹覆盖",1366 "Sprite Folder Override": "表情文件夹覆盖",
1357 "Use a forward slash to specify a subfolder. Example: _space": "使用正斜杠指定子文件夹。例如:",1367 "Use a forward slash to specify a subfolder. Example: _space": "使用正斜杠指定子文件夹。例如:",
1358 "Upload sprite pack (ZIP)": "上传表情包 (ZIP)",1368 "Upload sprite pack (ZIP)": "上传表情包(ZIP)",
1359 "Remove all image overrides": "删除所有图片覆盖",1369 "Remove all image overrides": "删除所有图片覆盖",
1360 "Create new folder in the _space": "创建新文件夹到",1370 "Create new folder in the _space": "创建新文件夹到",
1361 "folder of your user data directory and name it as the name of the character.": "用户数据目录的文件夹并将其命名为角色的名称。",1371 "folder of your user data directory and name it as the name of the character.": "用户数据目录的文件夹并将其命名为角色的名称。",
@@ -1460,12 +1470,12 @@
1460 "ext_regex_global_scripts": "全局正则脚本",1470 "ext_regex_global_scripts": "全局正则脚本",
1461 "ext_regex_global_scripts_desc": "影响所有角色,保存在本地设定中",1471 "ext_regex_global_scripts_desc": "影响所有角色,保存在本地设定中",
1462 "ext_regex_scoped_scripts": "局部正则脚本",1472 "ext_regex_scoped_scripts": "局部正则脚本",
1463 "ext_regex_disallow_scoped": "Disallow using scoped regex",1473 "ext_regex_disallow_scoped": "不允许使用局部正则",
1464 "ext_regex_allow_scoped": "允许使用范围正则表达式",1474 "ext_regex_allow_scoped": "允许使用局部正则",
1465 "ext_regex_scoped_scripts_desc": "只影响当前角色,保存在角色卡片中",1475 "ext_regex_scoped_scripts_desc": "只影响当前角色,保存在角色卡片中",
1466 "Regex Editor": "正则表达式编辑器",1476 "Regex Editor": "正则表达式编辑器",
1467 "Test Mode": "测试模式",1477 "Test Mode": "测试模式",
1468 "ext_regex_desc": "正则是一款使用正则表达式查找/替换字符串的工具。如果您想了解更多信息,请点击标题旁边的 ?。",1478 "ext_regex_desc": "“正则”是一个使用“正则表达式”来查找/替换字符串的工具。如果您想了解更多信息,请点击标题旁边的“?”。",
1469 "Input": "输入",1479 "Input": "输入",
1470 "ext_regex_test_input_placeholder": "在此输入...",1480 "ext_regex_test_input_placeholder": "在此输入...",
1471 "Output": "输出",1481 "Output": "输出",
@@ -1566,7 +1576,7 @@
1566 "Click to set": "点击设置",1576 "Click to set": "点击设置",
1567 "You can find your API key in the Stability AI dashboard.": "您可以在 Stability AI 仪表板中找到您的 API 密钥。",1577 "You can find your API key in the Stability AI dashboard.": "您可以在 Stability AI 仪表板中找到您的 API 密钥。",
1568 "Style Preset": "风格预设",1578 "Style Preset": "风格预设",
1569 "Prompt Upsampling": "Prompt Upsampling",1579 "Prompt Upsampling": "提示词增强(Upsampling)",
1570 "Sampling method": "采样方法",1580 "Sampling method": "采样方法",
1571 "Scheduler": "调度器",1581 "Scheduler": "调度器",
1572 "Resolution": "分辨率",1582 "Resolution": "分辨率",
@@ -1584,7 +1594,7 @@
1584 "Karras": "Karras",1594 "Karras": "Karras",
1585 "Not all samplers supported.": "并非所有采样器都受支持。",1595 "Not all samplers supported.": "并非所有采样器都受支持。",
1586 "sd_adetailer_face": "Use ADetailer with face model during the generation. The ADetailer extension must be installed on the backend.",1596 "sd_adetailer_face": "Use ADetailer with face model during the generation. The ADetailer extension must be installed on the backend.",
1587 "Use ADetailer (Face)": "使用 ADetailer (Face)",1597 "Use ADetailer (Face)": "使用 ADetailer(脸部)",
1588 "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA 版本的采样器经过修改,在高分辨率下性能更佳。",1598 "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA 版本的采样器经过修改,在高分辨率下性能更佳。",
1589 "SMEA": "中小企业协会",1599 "SMEA": "中小企业协会",
1590 "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 采样器的 DYN 变体通常会产生更加多样化的输出,但在非常高的分辨率下可能会失败。",1600 "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 采样器的 DYN 变体通常会产生更加多样化的输出,但在非常高的分辨率下可能会失败。",
@@ -1627,9 +1637,9 @@
1627 "Select TTS Provider": "选择 文本转语音 的服务提供商",1637 "Select TTS Provider": "选择 文本转语音 的服务提供商",
1628 "tts_enabled": "已启用",1638 "tts_enabled": "已启用",
1629 "Narrate user messages": "朗读用户消息",1639 "Narrate user messages": "朗读用户消息",
1630 "Auto Generation": "Auto Generation",1640 "Auto Generation": "自动生成",
1631 "Requires auto generation to be enabled.": "Requires auto generation to be enabled.",1641 "Requires auto generation to be enabled.": "需要启用自动生成功能。",
1632 "Narrate by paragraphs (when streaming)": "Narrate by paragraphs (when streaming)",1642 "Narrate by paragraphs (when streaming)": "按段朗读(流式播放时)",
1633 "Only narrate quotes": "只朗读引号内文本",1643 "Only narrate quotes": "只朗读引号内文本",
1634 "Ignore text, even quotes, inside asterisk": "不朗读所有*星号内文本*,即使其被引号包裹",1644 "Ignore text, even quotes, inside asterisk": "不朗读所有*星号内文本*,即使其被引号包裹",
1635 "Narrate only the translated text": "只朗读翻译后文本",1645 "Narrate only the translated text": "只朗读翻译后文本",
@@ -1658,9 +1668,9 @@
1658 "Enable for files": "为文件启用",1668 "Enable for files": "为文件启用",
1659 "Translate files into English before processing": "处理之前将文件翻译成英文",1669 "Translate files into English before processing": "处理之前将文件翻译成英文",
1660 "Message attachments": "消息附件",1670 "Message attachments": "消息附件",
1661 "Size threshold (KB)": "大小阈值 (KB)",1671 "Size threshold (KB)": "大小阈值(KB)",
1662 "Chunk size (chars)": "块大小(字符)",1672 "Chunk size (chars)": "块大小(字符)",
1663 "Chunk overlap (%)": "块重叠 (%)",1673 "Chunk overlap (%)": "块重叠(%)",
1664 "Retrieve chunks": "检索块",1674 "Retrieve chunks": "检索块",
1665 "Data Bank files": "数据库文件",1675 "Data Bank files": "数据库文件",
1666 "Injection Template": "注入模板",1676 "Injection Template": "注入模板",
@@ -1691,6 +1701,7 @@
1691 "This will create a new subfolder...": "这将在 /data/ 目录中创建一个新的子文件夹,以用户的句柄作为文件夹名称。",1701 "This will create a new subfolder...": "这将在 /data/ 目录中创建一个新的子文件夹,以用户的句柄作为文件夹名称。",
1692 "Note:": "提示:",1702 "Note:": "提示:",
1693 "this chat is temporary and will be deleted as soon as you leave it.": "此聊天会话是临时的,会在你离开时被删除。",1703 "this chat is temporary and will be deleted as soon as you leave it.": "此聊天会话是临时的,会在你离开时被删除。",
1704 "Enter a new display name:": "输入一个新的昵称:",
1694 "Current Password:": "当前密码:",1705 "Current Password:": "当前密码:",
1695 "New Password:": "新密码:",1706 "New Password:": "新密码:",
1696 "Confirm New Password:": "确认新密码:",1707 "Confirm New Password:": "确认新密码:",
@@ -1711,22 +1722,25 @@
1711 "chat_rename_1": "输入聊天的新名称:",1722 "chat_rename_1": "输入聊天的新名称:",
1712 "chat_rename_2": "注意!!使用已有文件名会导致错误!!",1723 "chat_rename_2": "注意!!使用已有文件名会导致错误!!",
1713 "chat_rename_3": "此举会将次聊天与标记为“检查点”的聊天解绑。",1724 "chat_rename_3": "此举会将次聊天与标记为“检查点”的聊天解绑。",
1714 "chat_rename_4": "不需要在结尾添加 '.jsonl'",1725 "chat_rename_4": "不需要在结尾添加 '.JSONL'",
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.": "当前检查点将会被解绑并替换为新的检查点,但仍可在聊天管理中找到。",
1715 "Include Body Parameters": "包括主体参数",1729 "Include Body Parameters": "包括主体参数",
1716 "custom_include_body_desc": "聊天完成请求主体中要包含的参数(YAML 对象)\n\n示例:\n- top_k:20\n- repetition_penalty:1.1",1730 "custom_include_body_desc": "聊天完成请求主体中要包含的参数(YAML 对象)\n\n示例:\n- top_k:20\n- repetition_penalty:1.1",
1717 "Exclude Body Parameters": "排除主体参数",1731 "Exclude Body Parameters": "排除主体参数",
1718 "custom_exclude_body_desc": "要从聊天完成请求主体中排除的参数(YAML 数组)\n\n示例:\n- frequency_penalty\n- presence_penalty",1732 "custom_exclude_body_desc": "要从聊天完成请求主体中排除的参数(YAML 数组)\n\n示例:\n- frequency_penalty\n- presence_penalty",
1719 "Include Request Headers": "包含请求标头",1733 "Include Request Headers": "包含请求标头",
1720 "custom_include_headers_desc": "聊天完成请求的附加标头(YAML 对象)\n\n示例:\n- CustomHeader:自定义值\n- AnotherHeader:自定义值",1734 "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.": "此类别中的功能仅供高级用户使用。如果您不确定后果,请不要点击任何内容。",
1722 "THIS IS PERMANENT!": "此操作不可逆!",1736 "THIS IS PERMANENT!": "此操作不可逆!",
1723 "Also delete the chat files": "同时删除聊天文件",1737 "Also delete the chat files": "同时删除聊天文件",
1724 "Are you sure you want to delete this user?": "您确定要删除该用户吗?",1738 "Are you sure you want to delete this user?": "您确定要删除该用户吗?",
1725 "Deleting:": "删除:",1739 "Deleting:": "删除:",
1726 "Also wipe user data.": "也清空用户数据。",1740 "Also wipe user data.": "同时清空用户数据",
1727 "Warning:": "警告:",1741 "Warning:": "警告:",
1728 "This action is irreversible.": "此操作不可逆。",1742 "This action is irreversible.": "此操作不可逆。",
1729 "Type the user's handle below to confirm:": "在下面输入用户的名称以确认:",1743 "Type the user's handle below to confirm:": "在下面输入此用户的用户句柄以确认删除操作:",
1730 "Are you sure you want to duplicate this character?": "你确定要复制这个角色吗?",1744 "Are you sure you want to duplicate this character?": "你确定要复制这个角色吗?",
1731 "If you just want to start a new chat with the same character...": "如果你只是想要与此角色开启一个新的聊天,只需点击聊天左下方菜单中的“开始新聊天”按钮。",1745 "If you just want to start a new chat with the same character...": "如果你只是想要与此角色开启一个新的聊天,只需点击聊天左下方菜单中的“开始新聊天”按钮。",
1732 "Forbid Media Override explanation": "当前角色/群聊成员使用外部媒体的能力。",1746 "Forbid Media Override explanation": "当前角色/群聊成员使用外部媒体的能力。",
@@ -1764,11 +1778,11 @@
1764 "help_format_26": "内联代码",1778 "help_format_26": "内联代码",
1765 "help_format_27": "> 文本",1779 "help_format_27": "> 文本",
1766 "help_format_28": "显示为块引用(请注意 > 后面的空格)",1780 "help_format_28": "显示为块引用(请注意 > 后面的空格)",
1767 "help_format_29": "# 文本",1781 "help_format_29": "# 文本",
1768 "help_format_30": "显示为大标题(注意空格)",1782 "help_format_30": "显示为大标题(注意空格)",
1769 "help_format_32": "## 文本",1783 "help_format_32": "## 文本",
1770 "help_format_33": "显示为中等标题(注意空格)",1784 "help_format_33": "显示为中等标题(注意空格)",
1771 "help_format_35": "### 文本",1785 "help_format_35": "### 文本",
1772 "help_format_36": "显示为小标题(注意空格)",1786 "help_format_36": "显示为小标题(注意空格)",
1773 "help_1": "您好!请选择您想要详细了解的帮助主题:",1787 "help_1": "您好!请选择您想要详细了解的帮助主题:",
1774 "help_2": "斜线命令",1788 "help_2": "斜线命令",
@@ -1821,9 +1835,27 @@
1821 "char_import_8": "RisuRealm 角色(直链)",1835 "char_import_8": "RisuRealm 角色(直链)",
1822 "Supports importing multiple characters.": "支持导入多个角色。",1836 "Supports importing multiple characters.": "支持导入多个角色。",
1823 "Write each URL or ID into a new line.": "将每个 URL 或 ID 写入新行。",1837 "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 以安装",
1825 "Copy Prompt": "复制提示",1839 "Disclaimer:": "免责声明:",
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 ":": ":",
1827 "System-wide Replacement Macros (in order of evaluation):": "系统范围的替换宏(按评估顺序):",1859 "System-wide Replacement Macros (in order of evaluation):": "系统范围的替换宏(按评估顺序):",
1828 "help_macros_1": "仅适用于斜线命令批处理。替换为上一个命令的返回结果。",1860 "help_macros_1": "仅适用于斜线命令批处理。替换为上一个命令的返回结果。",
1829 "help_macros_2": "仅插入一个换行符。",1861 "help_macros_2": "仅插入一个换行符。",
@@ -1913,7 +1945,9 @@
1913 "help_macros_68": "替换为全局变量“name”的值减 1 的结果",1945 "help_macros_68": "替换为全局变量“name”的值减 1 的结果",
1914 "help_macros_69": "替换为范围变量“name”的值",1946 "help_macros_69": "替换为范围变量“name”的值",
1915 "help_macros_70": "用范围变量“name”的索引处的项目值(对于数组/列表或对象/字典)替换",1947 "help_macros_70": "用范围变量“name”的索引处的项目值(对于数组/列表或对象/字典)替换",
1948 "Choose what to export": "选择您想要导出什么:",
1916 "{{name}}": "{{name}}",1949 "{{name}}": "{{name}}",
1950 "Choose what to import": "选择您想要导入什么:",
1917 "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可稍后在 /backups 文件夹中恢复此聊天文件。",1951 "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可稍后在 /backups 文件夹中恢复此聊天文件。",
1918 "Also delete the current chat file": "同时删除当前聊天文件",1952 "Also delete the current chat file": "同时删除当前聊天文件",
1919 "Persona Lorebook for": "Persona Lorebook for",1953 "Persona Lorebook for": "Persona Lorebook for",
@@ -1938,8 +1972,13 @@
1938 "If you have sufficient credits, please try again later.": "若您有足够的余额,请稍后再试。",1972 "If you have sufficient credits, please try again later.": "若您有足够的余额,请稍后再试。",
1939 "Are you sure you want to reset your settings to factory defaults?": "您确定要将您的设置重置为出厂默认设置吗?",1973 "Are you sure you want to reset your settings to factory defaults?": "您确定要将您的设置重置为出厂默认设置吗?",
1940 "Don't forget to save a snapshot of your settings before proceeding.": "在继续之前,不要忘记保存您的设置快照。",1974 "Don't forget to save a snapshot of your settings before proceeding.": "在继续之前,不要忘记保存您的设置快照。",
1975 "Enter your password below to confirm:": "输入您的密码以确认:",
1941 "Chat Scenario Override": "聊天场景覆盖",1976 "Chat Scenario Override": "聊天场景覆盖",
1942 "Remove": "移除",1977 "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.",
1943 "Settings Snapshots": "设置快照",1982 "Settings Snapshots": "设置快照",
1944 "Record a snapshot of your current settings.": "记录当前设置的快照。",1983 "Record a snapshot of your current settings.": "记录当前设置的快照。",
1945 "Make a Snapshot": "制作快照",1984 "Make a Snapshot": "制作快照",
@@ -1962,6 +2001,7 @@
1962 "Click on the folder icon to use this tag as a folder.": "点击文件夹图标来将此标签作为一个文件夹。",2001 "Click on the folder icon to use this tag as a folder.": "点击文件夹图标来将此标签作为一个文件夹。",
1963 "Use alphabetical sorting": "按字母顺序排列",2002 "Use alphabetical sorting": "按字母顺序排列",
1964 "tags_sorting_desc": "启用后,标签在创建或重命名时会自动按字母顺序排序。\n禁用后,新标签会追加到末尾。\n\n如果通过拖动手动重新排列标签,则自动排序将被禁用。",2003 "tags_sorting_desc": "启用后,标签在创建或重命名时会自动按字母顺序排序。\n禁用后,新标签会追加到末尾。\n\n如果通过拖动手动重新排列标签,则自动排序将被禁用。",
2004 "Are you sure you want to delete the theme?": "你确定要删除这个主题吗?",
1965 "Hi,": "嗨,",2005 "Hi,": "嗨,",
1966 "To enable multi-account features, restart the SillyTavern server with": "要启用多帐户功能,请使用以下命令重新启动 SillyTavern 服务器",2006 "To enable multi-account features, restart the SillyTavern server with": "要启用多帐户功能,请使用以下命令重新启动 SillyTavern 服务器",
1967 "set to true in the config.yaml file.": "在 config.yaml 文件中设置为 true。",2007 "set to true in the config.yaml file.": "在 config.yaml 文件中设置为 true。",
@@ -1982,6 +2022,8 @@
1982 "Reset Settings": "重置设置",2022 "Reset Settings": "重置设置",
1983 "Wipe all user data and reset your account to factory settings.": "删除所有用户数据并将您的账号重置为默认设置。",2023 "Wipe all user data and reset your account to factory settings.": "删除所有用户数据并将您的账号重置为默认设置。",
1984 "Reset Everything": "重置一切",2024 "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.",
1985 "Reset Code:": "重置代码:",2027 "Reset Code:": "重置代码:",
1986 "Want to update?": "获取最新版本",2028 "Want to update?": "获取最新版本",
1987 "How to start chatting?": "如何快速开始聊天?",2029 "How to start chatting?": "如何快速开始聊天?",
public/locales/zh-tw.json+2 -2
@@ -880,7 +880,7 @@
880 "popup-button-no": "取消",880 "popup-button-no": "取消",
881 "popup-button-cancel": "關閉",881 "popup-button-cancel": "關閉",
882 "popup-button-import": "匯入",882 "popup-button-import": "匯入",
883 "Advanced Defininitions": "- 進階定義",883 "Advanced Definitions": "- 進階定義",
884 "Prompt Overrides": "提示詞覆寫",884 "Prompt Overrides": "提示詞覆寫",
885 "(For Chat Completion and Instruct Mode)": "(用於聊天補全和指令模式)",885 "(For Chat Completion and Instruct Mode)": "(用於聊天補全和指令模式)",
886 "Insert {{original}} into either box to include the respective default prompt from system settings.": "在任一框中插入 {{original}} 以包含系統設定中的預設提示詞。",886 "Insert {{original}} into either box to include the respective default prompt from system settings.": "在任一框中插入 {{original}} 以包含系統設定中的預設提示詞。",
@@ -1454,7 +1454,7 @@
1454 "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)",1454 "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)",
1455 "comma delimited,no spaces between": "逗號分割,無需空格",1455 "comma delimited,no spaces between": "逗號分割,無需空格",
1456 "e.g. black-forest-labs/FLUX.1-dev": "例如:black-forest-labs/FLUX.1-dev",1456 "e.g. black-forest-labs/FLUX.1-dev": "例如:black-forest-labs/FLUX.1-dev",
1457 "Example: gpt-3.5-turbo": "例如:gpt-3.5-turbo",1457 "Example: gpt-4o": "例如:gpt-4o",
1458 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",1458 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",
1459 "popup-button-crop": "裁剪",1459 "popup-button-crop": "裁剪",
1460 "(disabled when max recursion steps are used)": "(當最大遞歸步驟數使用時將停用)",1460 "(disabled when max recursion steps are used)": "(當最大遞歸步驟數使用時將停用)",
public/script.js+104 -24
@@ -574,7 +574,7 @@ export const DEFAULT_SAVE_EDIT_TIMEOUT = debounce_timeout.relaxed;
574/** @type {debounce_timeout} The debounce timeout used for printing. debounce_timeout.quick: 100 ms */574/** @type {debounce_timeout} The debounce timeout used for printing. debounce_timeout.quick: 100 ms */
575export const DEFAULT_PRINT_TIMEOUT = debounce_timeout.quick;575export const DEFAULT_PRINT_TIMEOUT = debounce_timeout.quick;
576576
577export const saveSettingsDebounced = debounce(() => saveSettings(), DEFAULT_SAVE_EDIT_TIMEOUT);577export const saveSettingsDebounced = debounce((loopCounter = 0) => saveSettings(loopCounter), DEFAULT_SAVE_EDIT_TIMEOUT);
578export const saveCharacterDebounced = debounce(() => $('#create_button').trigger('click'), DEFAULT_SAVE_EDIT_TIMEOUT);578export const saveCharacterDebounced = debounce(() => $('#create_button').trigger('click'), DEFAULT_SAVE_EDIT_TIMEOUT);
579579
580/**580/**
@@ -2724,7 +2724,7 @@ export function getStoppingStrings(isImpersonate, isContinue) {
2724export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, quietImage = null, quietName = null, responseLength = null, force_chid = null) {2724export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, quietImage = null, quietName = null, responseLength = null, force_chid = null) {
2725 console.log('got into genQuietPrompt');2725 console.log('got into genQuietPrompt');
2726 const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0;2726 const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0;
2727 let originalResponseLength = -1;2727 let eventHook = () => {};
2728 try {2728 try {
2729 /** @type {GenerateOptions} */2729 /** @type {GenerateOptions} */
2730 const options = {2730 const options = {
@@ -2736,11 +2736,15 @@ export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, q
2736 quietName: quietName,2736 quietName: quietName,
2737 force_chid: force_chid,2737 force_chid: force_chid,
2738 };2738 };
2739 originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1;2739 if (responseLengthCustomized) {
2740 TempResponseLength.save(main_api, responseLength);
2741 eventHook = TempResponseLength.setupEventHook(main_api);
2742 }
2740 return await Generate('quiet', options);2743 return await Generate('quiet', options);
2741 } finally {2744 } finally {
2742 if (responseLengthCustomized) {2745 if (responseLengthCustomized && TempResponseLength.isCustomized()) {
2743 restoreResponseLength(main_api, originalResponseLength);2746 TempResponseLength.restore(main_api);
2747 TempResponseLength.removeEventHook(main_api, eventHook);
2744 }2748 }
2745 }2749 }
2746}2750}
@@ -3384,9 +3388,9 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
33843388
3385 const abortController = new AbortController();3389 const abortController = new AbortController();
3386 const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0;3390 const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0;
3387 let originalResponseLength = -1;
3388 const isInstruct = power_user.instruct.enabled && api !== 'openai' && api !== 'novel' && !instructOverride;3391 const isInstruct = power_user.instruct.enabled && api !== 'openai' && api !== 'novel' && !instructOverride;
3389 const isQuiet = true;3392 const isQuiet = true;
3393 let eventHook = () => {};
33903394
3391 if (systemPrompt) {3395 if (systemPrompt) {
3392 systemPrompt = substituteParams(systemPrompt);3396 systemPrompt = substituteParams(systemPrompt);
@@ -3400,7 +3404,9 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
3400 prompt = isInstruct ? (prompt + formatInstructModePrompt(name2, false, '', name1, name2, isQuiet, quietToLoud)) : (prompt + '\n');3404 prompt = isInstruct ? (prompt + formatInstructModePrompt(name2, false, '', name1, name2, isQuiet, quietToLoud)) : (prompt + '\n');
34013405
3402 try {3406 try {
3403 originalResponseLength = responseLengthCustomized ? saveResponseLength(api, responseLength) : -1;3407 if (responseLengthCustomized) {
3408 TempResponseLength.save(api, responseLength);
3409 }
3404 let generateData = {};3410 let generateData = {};
34053411
3406 switch (api) {3412 switch (api) {
@@ -3413,20 +3419,24 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
3413 const koboldSettings = koboldai_settings[koboldai_setting_names[preset_settings]];3419 const koboldSettings = koboldai_settings[koboldai_setting_names[preset_settings]];
3414 generateData = getKoboldGenerationData(prompt, koboldSettings, amount_gen, max_context, isHorde, 'quiet');3420 generateData = getKoboldGenerationData(prompt, koboldSettings, amount_gen, max_context, isHorde, 'quiet');
3415 }3421 }
3422 TempResponseLength.restore(api);
3416 break;3423 break;
3417 case 'novel': {3424 case 'novel': {
3418 const novelSettings = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]];3425 const novelSettings = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]];
3419 generateData = getNovelGenerationData(prompt, novelSettings, amount_gen, false, false, null, 'quiet');3426 generateData = getNovelGenerationData(prompt, novelSettings, amount_gen, false, false, null, 'quiet');
3427 TempResponseLength.restore(api);
3420 break;3428 break;
3421 }3429 }
3422 case 'textgenerationwebui':3430 case 'textgenerationwebui':
3423 generateData = getTextGenGenerationData(prompt, amount_gen, false, false, null, 'quiet');3431 generateData = getTextGenGenerationData(prompt, amount_gen, false, false, null, 'quiet');
3432 TempResponseLength.restore(api);
3424 break;3433 break;
3425 case 'openai': {3434 case 'openai': {
3426 generateData = [{ role: 'user', content: prompt.trim() }];3435 generateData = [{ role: 'user', content: prompt.trim() }];
3427 if (systemPrompt) {3436 if (systemPrompt) {
3428 generateData.unshift({ role: 'system', content: systemPrompt.trim() });3437 generateData.unshift({ role: 'system', content: systemPrompt.trim() });
3429 }3438 }
3439 eventHook = TempResponseLength.setupEventHook(api);
3430 } break;3440 } break;
3431 }3441 }
34323442
@@ -3468,41 +3478,100 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
34683478
3469 return message;3479 return message;
3470 } finally {3480 } finally {
3471 if (responseLengthCustomized) {3481 if (responseLengthCustomized && TempResponseLength.isCustomized()) {
3472 restoreResponseLength(api, originalResponseLength);3482 TempResponseLength.restore(api);
3483 TempResponseLength.removeEventHook(api, eventHook);
3473 }3484 }
3474 }3485 }
3475}3486}
34763487
3488class TempResponseLength {
3489 static #originalResponseLength = -1;
3490 static #lastApi = null;
3491
3492 static isCustomized() {
3493 return this.#originalResponseLength > -1;
3494 }
3495
3477 /**3496 /**
3478 * Temporarily change the response length for the specified API.3497 * Save the current response length for the specified API.
3479 * @param {string} api API to use.3498 * @param {string} api API identifier
3480 * @param {number} responseLength Target response length.3499 * @param {number} responseLength New response length
3481 * @returns {number} The original response length.
3482 */3500 */
3483function saveResponseLength(api, responseLength) {3501 static save(api, responseLength) {
3484 let oldValue = -1;
3485 if (api === 'openai') {3502 if (api === 'openai') {
3486 oldValue = oai_settings.openai_max_tokens;3503 this.#originalResponseLength = oai_settings.openai_max_tokens;
3487 oai_settings.openai_max_tokens = responseLength;3504 oai_settings.openai_max_tokens = responseLength;
3488 } else {3505 } else {
3489 oldValue = amount_gen;3506 this.#originalResponseLength = amount_gen;
3490 amount_gen = responseLength;3507 amount_gen = responseLength;
3491 }3508 }
3492 return oldValue;3509
3510 this.#lastApi = api;
3511 console.log('[TempResponseLength] Saved original response length:', TempResponseLength.#originalResponseLength);
3493 }3512 }
34943513
3495 /**3514 /**
3496 * Restore the original response length for the specified API.3515 * Restore the original response length for the specified API.
3497 * @param {string} api API to use.3516 * @param {string|null} api API identifier
3498 * @param {number} responseLength Target response length.
3499 * @returns {void}3517 * @returns {void}
3500 */3518 */
3501function restoreResponseLength(api, responseLength) {3519 static restore(api) {
3520 if (this.#originalResponseLength === -1) {
3521 return;
3522 }
3523 if (!api && this.#lastApi) {
3524 api = this.#lastApi;
3525 }
3502 if (api === 'openai') {3526 if (api === 'openai') {
3503 oai_settings.openai_max_tokens = responseLength;3527 oai_settings.openai_max_tokens = this.#originalResponseLength;
3504 } else {3528 } else {
3505 amount_gen = responseLength;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 }
3506 }3575 }
3507}3576}
35083577
@@ -6865,12 +6934,23 @@ function selectKoboldGuiPreset() {
6865 .trigger('change');6934 .trigger('change');
6866}6935}
68676936
6868export async function saveSettings(type) {6937export async function saveSettings(loopCounter = 0) {
6869 if (!settingsReady) {6938 if (!settingsReady) {
6870 console.warn('Settings not ready, aborting save');6939 console.warn('Settings not ready, aborting save');
6871 return;6940 return;
6872 }6941 }
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
6874 //console.log('Entering settings with name1 = '+name1);6954 //console.log('Entering settings with name1 = '+name1);
6875 return jQuery.ajax({6955 return jQuery.ajax({
6876 type: 'POST',6956 type: 'POST',
public/scripts/extensions.js+11 -11
@@ -682,9 +682,9 @@ function getExtensionData(extension) {
682 * @return {string} - The HTML string for the module information.682 * @return {string} - The HTML string for the module information.
683 */683 */
684function getModuleInformation() {684function getModuleInformation() {
685 let moduleInfo = modules.length ? `<p>${DOMPurify.sanitize(modules.join(', '))}</p>` : '<p class="failure">Not connected to the API!</p>';685 let moduleInfo = modules.length ? `<p>${DOMPurify.sanitize(modules.join(', '))}</p>` : '<p class="failure">' + t`Not connected to the API!` + '</p>';
686 return `686 return `
687 <h3>Modules provided by your Extras API:</h3>687 <h3>` + t`Modules provided by your Extras API:` + `</h3>
688 ${moduleInfo}688 ${moduleInfo}
689 `;689 `;
690}690}
@@ -703,11 +703,11 @@ async function showExtensionsDetails() {
703 initialScrollTop = oldPopup.content.scrollTop;703 initialScrollTop = oldPopup.content.scrollTop;
704 await oldPopup.completeCancelled();704 await oldPopup.completeCancelled();
705 }705 }
706 const htmlDefault = $('<div class="marginBot10"><h3 class="textAlignCenter">Built-in Extensions:</h3></div>');706 const htmlDefault = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Built-in Extensions:` + '</h3></div>');
707 const htmlExternal = $('<div class="marginBot10"><h3 class="textAlignCenter">Installed Extensions:</h3></div>');707 const htmlExternal = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Installed Extensions:` + '</h3></div>');
708 const htmlLoading = $(`<div class="flex-container alignItemsCenter justifyCenter marginTop10 marginBot5">708 const htmlLoading = $(`<div class="flex-container alignItemsCenter justifyCenter marginTop10 marginBot5">
709 <i class="fa-solid fa-spinner fa-spin"></i>709 <i class="fa-solid fa-spinner fa-spin"></i>
710 <span>Loading third-party extensions... Please wait...</span>710 <span>` + t`Loading third-party extensions... Please wait...` + `</span>
711 </div>`);711 </div>`);
712712
713 htmlExternal.append(htmlLoading);713 htmlExternal.append(htmlLoading);
@@ -728,7 +728,7 @@ async function showExtensionsDetails() {
728728
729 /** @type {import('./popup.js').CustomPopupButton} */729 /** @type {import('./popup.js').CustomPopupButton} */
730 const updateAllButton = {730 const updateAllButton = {
731 text: 'Update all',731 text: t`Update all`,
732 appendAtEnd: true,732 appendAtEnd: true,
733 action: async () => {733 action: async () => {
734 requiresReload = true;734 requiresReload = true;
@@ -740,7 +740,7 @@ async function showExtensionsDetails() {
740 let waitingForSave = false;740 let waitingForSave = false;
741741
742 const popup = new Popup(html, POPUP_TYPE.TEXT, '', {742 const popup = new Popup(html, POPUP_TYPE.TEXT, '', {
743 okButton: 'Close',743 okButton: t`Close`,
744 wide: true,744 wide: true,
745 large: true,745 large: true,
746 customButtons: [updateAllButton],746 customButtons: [updateAllButton],
@@ -833,7 +833,7 @@ async function updateExtension(extensionName, quiet) {
833 toastr.success('Extension is already up to date');833 toastr.success('Extension is already up to date');
834 }834 }
835 } else {835 } else {
836 toastr.success(`Extension ${extensionName} updated to ${data.shortCommitHash}`, 'Reload the page to apply updates');836 toastr.success(t`Extension ${extensionName} updated to ${data.shortCommitHash}`, t`Reload the page to apply updates`);
837 }837 }
838 } catch (error) {838 } catch (error) {
839 console.error('Error:', error);839 console.error('Error:', error);
@@ -1001,7 +1001,7 @@ export async function installExtension(url, global) {
1001 }1001 }
10021002
1003 const response = await request.json();1003 const response = await request.json();
1004 toastr.success(`Extension "${response.display_name}" by ${response.author} (version ${response.version}) has been installed successfully!`, 'Extension installation successful');1004 toastr.success(t`Extension '${response.display_name}' by ${response.author} (version ${response.version}) has been installed successfully!`, t`Extension installation successful`);
1005 console.debug(`Extension "${response.display_name}" has been installed successfully at ${response.extensionPath}`);1005 console.debug(`Extension "${response.display_name}" has been installed successfully at ${response.extensionPath}`);
1006 await loadExtensionSettings({}, false, false);1006 await loadExtensionSettings({}, false, false);
1007 await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED);1007 await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED);
@@ -1175,7 +1175,7 @@ async function checkForExtensionUpdates(force) {
1175 await Promise.allSettled(promises);1175 await Promise.allSettled(promises);
11761176
1177 if (updatesAvailable.length > 0) {1177 if (updatesAvailable.length > 0) {
1178 toastr.info(`${updatesAvailable.map(x => `• ${x}`).join('\n')}`, 'Extension updates available');1178 toastr.info(`${updatesAvailable.map(x => `• ${x}`).join('\n')}`, t`Extension updates available`);
1179 }1179 }
1180}1180}
11811181
@@ -1189,7 +1189,7 @@ async function autoUpdateExtensions(forceAll) {
1189 return;1189 return;
1190 }1190 }
11911191
1192 const banner = toastr.info('Auto-updating extensions. This may take several minutes.', 'Please wait...', { timeOut: 10000, extendedTimeOut: 10000 });1192 const banner = toastr.info(t`Auto-updating extensions. This may take several minutes.`, t`Please wait...`, { timeOut: 10000, extendedTimeOut: 10000 });
1193 const isCurrentUserAdmin = isAdmin();1193 const isCurrentUserAdmin = isAdmin();
1194 const promises = [];1194 const promises = [];
1195 for (const [id, manifest] of Object.entries(manifests)) {1195 for (const [id, manifest] of Object.entries(manifests)) {
public/scripts/extensions/connection-manager/edit.html+2 -2
@@ -1,10 +1,10 @@
1<div>1<div>
2 <h3>Included settings:</h3>2 <h3 data-i18n="Included settings:">Included settings:</h3>
3 <div class="justifyLeft flex-container flexFlowColumn flexNoGap">3 <div class="justifyLeft flex-container flexFlowColumn flexNoGap">
4 {{#each settings}}4 {{#each settings}}
5 <label class="checkbox_label">5 <label class="checkbox_label">
6 <input type="checkbox" value="{{@key}}" name="exclude"{{#if this}} checked{{/if}}>6 <input type="checkbox" value="{{@key}}" name="exclude"{{#if this}} checked{{/if}}>
7 <span>{{@key}}</span>7 <span data-i18n="{{@key}}">{{@key}}</span>
8 </label>8 </label>
9 {{/each}}9 {{/each}}
10 </div>10 </div>
public/scripts/extensions/connection-manager/profile.html+2 -2
@@ -12,8 +12,8 @@
12 </div>12 </div>
13 <div class="marginTop5">13 <div class="marginTop5">
14 <small>14 <small>
15 <b>Hint:</b>15 <b data-i18n="Hint:">Hint:</b>
16 <i>Click on the setting name to omit it from the profile.</i>16 <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>
17 </small>17 </small>
18 </div>18 </div>
19 <h3 data-i18n="Enter a name:">19 <h3 data-i18n="Enter a name:">
public/scripts/extensions/quick-reply/html/settings.html+2 -0
@@ -46,10 +46,12 @@
46 <div class="qr--title" data-i18n="Edit Quick Replies">Edit Quick Replies</div>46 <div class="qr--title" data-i18n="Edit Quick Replies">Edit Quick Replies</div>
47 <div class="qr--actions">47 <div class="qr--actions">
48 <select id="qr--set" class="text_pole"></select>48 <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>
49 <div class="qr--add menu_button menu_button_icon fa-solid fa-plus" id="qr--set-new" title="Create new quick reply set"></div>50 <div class="qr--add menu_button menu_button_icon fa-solid fa-plus" id="qr--set-new" title="Create new quick reply set"></div>
50 <div class="qr--add menu_button menu_button_icon fa-solid fa-file-import" id="qr--set-import" title="Import quick reply set"></div>51 <div class="qr--add menu_button menu_button_icon fa-solid fa-file-import" id="qr--set-import" title="Import quick reply set"></div>
51 <input type="file" id="qr--set-importFile" accept=".json" hidden>52 <input type="file" id="qr--set-importFile" accept=".json" hidden>
52 <div class="qr--add menu_button menu_button_icon fa-solid fa-file-export" id="qr--set-export" title="Export quick reply set"></div>53 <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>
53 <div class="qr--del menu_button menu_button_icon fa-solid fa-trash redWarningBG" id="qr--set-delete" title="Delete quick reply set"></div>55 <div class="qr--del menu_button menu_button_icon fa-solid fa-trash redWarningBG" id="qr--set-delete" title="Delete quick reply set"></div>
54 </div>56 </div>
55 </div>57 </div>
public/scripts/extensions/quick-reply/src/ui/SettingsUi.js+81 -5
@@ -1,4 +1,4 @@
1import { callPopup } from '../../../../../script.js';1import { Popup } from '../../../../popup.js';
2import { getSortableDelay } from '../../../../utils.js';2import { getSortableDelay } from '../../../../utils.js';
3import { log, warn } from '../../index.js';3import { log, warn } from '../../index.js';
4import { QuickReply } from '../QuickReply.js';4import { QuickReply } from '../QuickReply.js';
@@ -111,6 +111,7 @@ export class SettingsUi {
111111
112 prepareQrEditor() {112 prepareQrEditor() {
113 // qr editor113 // qr editor
114 this.dom.querySelector('#qr--set-rename').addEventListener('click', async () => this.renameQrSet());
114 this.dom.querySelector('#qr--set-new').addEventListener('click', async()=>this.addQrSet());115 this.dom.querySelector('#qr--set-new').addEventListener('click', async()=>this.addQrSet());
115 /**@type {HTMLInputElement}*/116 /**@type {HTMLInputElement}*/
116 const importFile = this.dom.querySelector('#qr--set-importFile');117 const importFile = this.dom.querySelector('#qr--set-importFile');
@@ -120,6 +121,7 @@ export class SettingsUi {
120 });121 });
121 this.dom.querySelector('#qr--set-import').addEventListener('click', ()=>importFile.click());122 this.dom.querySelector('#qr--set-import').addEventListener('click', ()=>importFile.click());
122 this.dom.querySelector('#qr--set-export').addEventListener('click', async () => this.exportQrSet());123 this.dom.querySelector('#qr--set-export').addEventListener('click', async () => this.exportQrSet());
124 this.dom.querySelector('#qr--set-duplicate').addEventListener('click', async () => this.duplicateQrSet());
123 this.dom.querySelector('#qr--set-delete').addEventListener('click', async()=>this.deleteQrSet());125 this.dom.querySelector('#qr--set-delete').addEventListener('click', async()=>this.deleteQrSet());
124 this.dom.querySelector('#qr--set-add').addEventListener('click', async()=>{126 this.dom.querySelector('#qr--set-add').addEventListener('click', async()=>{
125 this.currentQrSet.addQuickReply();127 this.currentQrSet.addQuickReply();
@@ -279,7 +281,7 @@ export class SettingsUi {
279 }281 }
280282
281 async deleteQrSet() {283 async deleteQrSet() {
282 const confirmed = await callPopup(`Are you sure you want to delete the Quick Reply Set "${this.currentQrSet.name}"?<br>This cannot be undone.`, 'confirm');284 const confirmed = await Popup.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.`);
283 if (confirmed) {285 if (confirmed) {
284 await this.doDeleteQrSet(this.currentQrSet);286 await this.doDeleteQrSet(this.currentQrSet);
285 this.rerender();287 this.rerender();
@@ -303,12 +305,52 @@ export class SettingsUi {
303 this.settings.save();305 this.settings.save();
304 }306 }
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
306 async addQrSet() {348 async addQrSet() {
307 const name = await callPopup('Quick Reply Set Name:', 'input');349 const name = await Popup.show.input('Create a new World Info', 'Enter a name for the new Quick Reply Set:');
308 if (name && name.length > 0) {350 if (name && name.length > 0) {
309 const oldQrs = QuickReplySet.get(name);351 const oldQrs = QuickReplySet.get(name);
310 if (oldQrs) {352 if (oldQrs) {
311 const replace = await callPopup(`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');353 const replace = Popup.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.`);
312 if (replace) {354 if (replace) {
313 const idx = QuickReplySet.list.indexOf(oldQrs);355 const idx = QuickReplySet.list.indexOf(oldQrs);
314 await this.doDeleteQrSet(oldQrs);356 await this.doDeleteQrSet(oldQrs);
@@ -369,7 +411,7 @@ export class SettingsUi {
369 qrs.init();411 qrs.init();
370 const oldQrs = QuickReplySet.get(props.name);412 const oldQrs = QuickReplySet.get(props.name);
371 if (oldQrs) {413 if (oldQrs) {
372 const replace = await callPopup(`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');414 const replace = Popup.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.`);
373 if (replace) {415 if (replace) {
374 const idx = QuickReplySet.list.indexOf(oldQrs);416 const idx = QuickReplySet.list.indexOf(oldQrs);
375 await this.doDeleteQrSet(oldQrs);417 await this.doDeleteQrSet(oldQrs);
@@ -421,6 +463,40 @@ export class SettingsUi {
421 URL.revokeObjectURL(url);463 URL.revokeObjectURL(url);
422 }464 }
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
424 selectQrSet(qrs) {500 selectQrSet(qrs) {
425 this.currentSet.value = qrs.name;501 this.currentSet.value = qrs.name;
426 this.onQrSetChange();502 this.onQrSetChange();
public/scripts/extensions/vectors/index.js+35 -3
@@ -30,6 +30,8 @@ import { textgen_types, textgenerationwebui_settings } from '../../textgen-setti
30import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';30import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
31import { SlashCommand } from '../../slash-commands/SlashCommand.js';31import { SlashCommand } from '../../slash-commands/SlashCommand.js';
32import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';32import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
33import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
34import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js';
33import { callGenericPopup, POPUP_RESULT, POPUP_TYPE } from '../../popup.js';35import { callGenericPopup, POPUP_RESULT, POPUP_TYPE } from '../../popup.js';
34import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js';36import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js';
3537
@@ -1613,25 +1615,55 @@ jQuery(async () => {
1613 callback: async (args, query) => {1615 callback: async (args, query) => {
1614 const clamp = (v) => Number.isNaN(v) ? null : Math.min(1, Math.max(0, v));1616 const clamp = (v) => Number.isNaN(v) ? null : Math.min(1, Math.max(0, v));
1615 const threshold = clamp(Number(args?.threshold ?? settings.score_threshold));1617 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;
1616 const source = String(args?.source ?? '');1620 const source = String(args?.source ?? '');
1617 const attachments = source ? getDataBankAttachmentsForSource(source, false) : getDataBankAttachments(false);1621 const attachments = source ? getDataBankAttachmentsForSource(source, false) : getDataBankAttachments(false);
1618 const collectionIds = await ingestDataBankAttachments(String(source));1622 const collectionIds = await ingestDataBankAttachments(String(source));
1619 const queryResults = await queryMultipleCollections(collectionIds, String(query), settings.chunk_count_db, threshold);1623 const queryResults = await queryMultipleCollections(collectionIds, String(query), count, threshold);
1620 1624
1621 // Map collection IDs to file URLs1625 // Get URLs
1622 const urls = Object1626 const urls = Object
1623 .keys(queryResults)1627 .keys(queryResults)
1624 .map(x => attachments.find(y => getFileCollectionId(y.url) === x))1628 .map(x => attachments.find(y => getFileCollectionId(y.url) === x))
1625 .filter(x => x)1629 .filter(x => x)
1626 .map(x => x.url);1630 .map(x => x.url);
1627 1631
1628 return JSON.stringify(urls);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 }
1645
1646 // @ts-ignore
1647 return slashCommandReturnHelper.doReturn(args.return ?? 'object', urls, { objectToStringFunc: list => list.join('\n') });
1648
1629 },1649 },
1630 aliases: ['databank-search', 'data-bank-search'],1650 aliases: ['databank-search', 'data-bank-search'],
1631 helpString: 'Search the Data Bank for a specific query using vector similarity. Returns a list of file URLs with the most relevant content.',1651 helpString: 'Search the Data Bank for a specific query using vector similarity. Returns a list of file URLs with the most relevant content.',
1632 namedArgumentList: [1652 namedArgumentList: [
1633 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, ''),1653 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, ''),
1634 new SlashCommandNamedArgument('source', 'Optional filter for the attachments by source.', ARGUMENT_TYPE.STRING, false, false, '', ['global', 'character', 'chat']),1655 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 })
1635 ],1667 ],
1636 unnamedArgumentList: [1668 unnamedArgumentList: [
1637 new SlashCommandArgument('Query to search by.', ARGUMENT_TYPE.STRING, true, false),1669 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 () {
26 * @typedef {(nonce: string) => string} MacroFunction26 * @typedef {(nonce: string) => string} MacroFunction
27 */27 */
2828
29/**
30 * @typedef {Object} CustomMacro
31 * @property {string} key - Macro name (key)
32 * @property {string} description - Optional description of the macro
33 */
34
29export class MacrosParser {35export class MacrosParser {
30 /**36 /**
31 * A map of registered macros.37 * A map of registered macros.
@@ -34,11 +40,28 @@ export class MacrosParser {
34 static #macros = new Map();40 static #macros = new Map();
3541
36 /**42 /**
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 /**
37 * Registers a global macro that can be used anywhere where substitution is allowed.59 * Registers a global macro that can be used anywhere where substitution is allowed.
38 * @param {string} key Macro name (key)60 * @param {string} key Macro name (key)
39 * @param {string|MacroFunction} value A string or a function that returns a string61 * @param {string|MacroFunction} value A string or a function that returns a string
62 * @param {string} [description] Optional description of the macro
40 */63 */
41 static registerMacro(key, value) {64 static registerMacro(key, value, description = '') {
42 if (typeof key !== 'string') {65 if (typeof key !== 'string') {
43 throw new Error('Macro key must be a string');66 throw new Error('Macro key must be a string');
44 }67 }
@@ -64,6 +87,10 @@ export class MacrosParser {
64 }87 }
6588
66 this.#macros.set(key, value);89 this.#macros.set(key, value);
90
91 if (typeof description === 'string' && description) {
92 this.#descriptions.set(key, description);
93 }
67 }94 }
6895
69 /**96 /**
@@ -88,6 +115,8 @@ export class MacrosParser {
88 if (!deleted) {115 if (!deleted) {
89 console.warn(`Macro ${key} was not registered`);116 console.warn(`Macro ${key} was not registered`);
90 }117 }
118
119 this.#descriptions.delete(key);
91 }120 }
92121
93 /**122 /**
public/scripts/openai.js+2 -2
@@ -5491,8 +5491,8 @@ export function initOpenAI() {
54915491
5492 if (!isMobile()) {5492 if (!isMobile()) {
5493 $('#model_openrouter_select').select2({5493 $('#model_openrouter_select').select2({
5494 placeholder: 'Select a model',5494 placeholder: t`Select a model`,
5495 searchInputPlaceholder: 'Search models...',5495 searchInputPlaceholder: t`Search models...`,
5496 searchInputCssClass: 'text_pole',5496 searchInputCssClass: 'text_pole',
5497 width: '100%',5497 width: '100%',
5498 templateResult: getOpenRouterModelTemplate,5498 templateResult: getOpenRouterModelTemplate,
public/scripts/slash-commands/SlashCommandParser.js+6 -0
@@ -22,6 +22,8 @@ import { SlashCommandBreakPoint } from './SlashCommandBreakPoint.js';
22import { SlashCommandDebugController } from './SlashCommandDebugController.js';22import { SlashCommandDebugController } from './SlashCommandDebugController.js';
23import { commonEnumProviders } from './SlashCommandCommonEnumsProvider.js';23import { commonEnumProviders } from './SlashCommandCommonEnumsProvider.js';
24import { SlashCommandBreak } from './SlashCommandBreak.js';24import { SlashCommandBreak } from './SlashCommandBreak.js';
25import { MacrosParser } from '../macros.js';
26import { t } from '../i18n.js';
2527
26/** @typedef {import('./SlashCommand.js').NamedArgumentsCapture} NamedArgumentsCapture */28/** @typedef {import('./SlashCommand.js').NamedArgumentsCapture} NamedArgumentsCapture */
27/** @typedef {import('./SlashCommand.js').NamedArguments} NamedArguments */29/** @typedef {import('./SlashCommand.js').NamedArguments} NamedArguments */
@@ -494,6 +496,10 @@ export class SlashCommandParser {
494 li.querySelector('tt').textContent,496 li.querySelector('tt').textContent,
495 (li.querySelector('tt').remove(),li.innerHTML),497 (li.querySelector('tt').remove(),li.innerHTML),
496 ));498 ));
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 }
497 const result = new AutoCompleteNameResult(503 const result = new AutoCompleteNameResult(
498 macro.name,504 macro.name,
499 macro.start + 2,505 macro.start + 2,
public/scripts/textgen-models.js+21 -20
@@ -5,6 +5,7 @@ import { textgenerationwebui_settings as textgen_settings, textgen_types } from
5import { tokenizers } from './tokenizers.js';5import { tokenizers } from './tokenizers.js';
6import { renderTemplateAsync } from './templates.js';6import { renderTemplateAsync } from './templates.js';
7import { POPUP_TYPE, callGenericPopup } from './popup.js';7import { POPUP_TYPE, callGenericPopup } from './popup.js';
8import { t } from './i18n.js';
89
9let mancerModels = [];10let mancerModels = [];
10let togetherModels = [];11let togetherModels = [];
@@ -936,71 +937,71 @@ export function initTextGenModels() {
936937
937 if (!isMobile()) {938 if (!isMobile()) {
938 $('#mancer_model').select2({939 $('#mancer_model').select2({
939 placeholder: 'Select a model',940 placeholder: t`Select a model`,
940 searchInputPlaceholder: 'Search models...',941 searchInputPlaceholder: t`Search models...`,
941 searchInputCssClass: 'text_pole',942 searchInputCssClass: 'text_pole',
942 width: '100%',943 width: '100%',
943 templateResult: getMancerModelTemplate,944 templateResult: getMancerModelTemplate,
944 });945 });
945 $('#model_togetherai_select').select2({946 $('#model_togetherai_select').select2({
946 placeholder: 'Select a model',947 placeholder: t`Select a model`,
947 searchInputPlaceholder: 'Search models...',948 searchInputPlaceholder: t`Search models...`,
948 searchInputCssClass: 'text_pole',949 searchInputCssClass: 'text_pole',
949 width: '100%',950 width: '100%',
950 templateResult: getTogetherModelTemplate,951 templateResult: getTogetherModelTemplate,
951 });952 });
952 $('#ollama_model').select2({953 $('#ollama_model').select2({
953 placeholder: 'Select a model',954 placeholder: t`Select a model`,
954 searchInputPlaceholder: 'Search models...',955 searchInputPlaceholder: t`Search models...`,
955 searchInputCssClass: 'text_pole',956 searchInputCssClass: 'text_pole',
956 width: '100%',957 width: '100%',
957 });958 });
958 $('#tabby_model').select2({959 $('#tabby_model').select2({
959 placeholder: '[Currently loaded]',960 placeholder: t`[Currently loaded]`,
960 searchInputPlaceholder: 'Search models...',961 searchInputPlaceholder: t`Search models...`,
961 searchInputCssClass: 'text_pole',962 searchInputCssClass: 'text_pole',
962 width: '100%',963 width: '100%',
963 allowClear: true,964 allowClear: true,
964 });965 });
965 $('#model_infermaticai_select').select2({966 $('#model_infermaticai_select').select2({
966 placeholder: 'Select a model',967 placeholder: t`Select a model`,
967 searchInputPlaceholder: 'Search models...',968 searchInputPlaceholder: t`Search models...`,
968 searchInputCssClass: 'text_pole',969 searchInputCssClass: 'text_pole',
969 width: '100%',970 width: '100%',
970 templateResult: getInfermaticAIModelTemplate,971 templateResult: getInfermaticAIModelTemplate,
971 });972 });
972 $('#model_dreamgen_select').select2({973 $('#model_dreamgen_select').select2({
973 placeholder: 'Select a model',974 placeholder: t`Select a model`,
974 searchInputPlaceholder: 'Search models...',975 searchInputPlaceholder: t`Search models...`,
975 searchInputCssClass: 'text_pole',976 searchInputCssClass: 'text_pole',
976 width: '100%',977 width: '100%',
977 templateResult: getDreamGenModelTemplate,978 templateResult: getDreamGenModelTemplate,
978 });979 });
979 $('#openrouter_model').select2({980 $('#openrouter_model').select2({
980 placeholder: 'Select a model',981 placeholder: t`Select a model`,
981 searchInputPlaceholder: 'Search models...',982 searchInputPlaceholder: t`Search models...`,
982 searchInputCssClass: 'text_pole',983 searchInputCssClass: 'text_pole',
983 width: '100%',984 width: '100%',
984 templateResult: getOpenRouterModelTemplate,985 templateResult: getOpenRouterModelTemplate,
985 });986 });
986 $('#vllm_model').select2({987 $('#vllm_model').select2({
987 placeholder: 'Select a model',988 placeholder: t`Select a model`,
988 searchInputPlaceholder: 'Search models...',989 searchInputPlaceholder: t`Search models...`,
989 searchInputCssClass: 'text_pole',990 searchInputCssClass: 'text_pole',
990 width: '100%',991 width: '100%',
991 templateResult: getVllmModelTemplate,992 templateResult: getVllmModelTemplate,
992 });993 });
993 $('#aphrodite_model').select2({994 $('#aphrodite_model').select2({
994 placeholder: 'Select a model',995 placeholder: t`Select a model`,
995 searchInputPlaceholder: 'Search models...',996 searchInputPlaceholder: t`Search models...`,
996 searchInputCssClass: 'text_pole',997 searchInputCssClass: 'text_pole',
997 width: '100%',998 width: '100%',
998 templateResult: getAphroditeModelTemplate,999 templateResult: getAphroditeModelTemplate,
999 });1000 });
1000 providersSelect.select2({1001 providersSelect.select2({
1001 sorter: data => data.sort((a, b) => a.text.localeCompare(b.text)),1002 sorter: data => data.sort((a, b) => a.text.localeCompare(b.text)),
1002 placeholder: 'Select providers. No selection = all providers.',1003 placeholder: t`Select providers. No selection = all providers.`,
1003 searchInputPlaceholder: 'Search providers...',1004 searchInputPlaceholder: t`Search providers...`,
1004 searchInputCssClass: 'text_pole',1005 searchInputCssClass: 'text_pole',
1005 width: '100%',1006 width: '100%',
1006 closeOnSelect: false,1007 closeOnSelect: false,
public/scripts/world-info.js+18 -17
@@ -20,6 +20,7 @@ import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
20import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js';20import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js';
21import { StructuredCloneMap } from './util/StructuredCloneMap.js';21import { StructuredCloneMap } from './util/StructuredCloneMap.js';
22import { renderTemplateAsync } from './templates.js';22import { renderTemplateAsync } from './templates.js';
23import { t } from './i18n.js';
2324
24export const world_info_insertion_strategy = {25export const world_info_insertion_strategy = {
25 evenly: 0,26 evenly: 0,
@@ -909,21 +910,21 @@ function registerWorldInfoSlashCommands() {
909910
910 async function getEntriesFromFile(file) {911 async function getEntriesFromFile(file) {
911 if (!file || !world_names.includes(file)) {912 if (!file || !world_names.includes(file)) {
912 toastr.warning('Valid World Info file name is required');913 toastr.warning(t`Valid World Info file name is required`);
913 return '';914 return '';
914 }915 }
915916
916 const data = await loadWorldInfo(file);917 const data = await loadWorldInfo(file);
917918
918 if (!data || !('entries' in data)) {919 if (!data || !('entries' in data)) {
919 toastr.warning('World Info file has an invalid format');920 toastr.warning(t`World Info file has an invalid format`);
920 return '';921 return '';
921 }922 }
922923
923 const entries = Object.values(data.entries);924 const entries = Object.values(data.entries);
924925
925 if (!entries || entries.length === 0) {926 if (!entries || entries.length === 0) {
926 toastr.warning('World Info file has no entries');927 toastr.warning(t`World Info file has no entries`);
927 return '';928 return '';
928 }929 }
929930
@@ -951,7 +952,7 @@ function registerWorldInfoSlashCommands() {
951 name = String(name ?? '') || context.characters[context.characterId]?.avatar || null;952 name = String(name ?? '') || context.characters[context.characterId]?.avatar || null;
952 const character = findChar({ name });953 const character = findChar({ name });
953 if (!character) {954 if (!character) {
954 toastr.error('Character not found.');955 toastr.error(t`Character not found.`);
955 return '';956 return '';
956 }957 }
957 const books = [];958 const books = [];
@@ -977,7 +978,7 @@ function registerWorldInfoSlashCommands() {
977 const chatId = getCurrentChatId();978 const chatId = getCurrentChatId();
978979
979 if (!chatId) {980 if (!chatId) {
980 toastr.warning('Open a chat to get a name of the chat-bound lorebook');981 toastr.warning(t`Open a chat to get a name of the chat-bound lorebook`);
981 return '';982 return '';
982 }983 }
983984
@@ -4773,7 +4774,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) {
4773 const bookName = characters[chid]?.data?.character_book?.name || `${characters[chid]?.name}'s Lorebook`;4774 const bookName = characters[chid]?.data?.character_book?.name || `${characters[chid]?.name}'s Lorebook`;
47744775
4775 if (!skipPopup) {4776 if (!skipPopup) {
4776 const confirmation = await Popup.show.confirm(`Are you sure you want to import "${bookName}"?`, world_names.includes(bookName) ? 'It will overwrite the World/Lorebook with the same name.' : '');4777 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.` : '');
4777 if (!confirmation) {4778 if (!confirmation) {
4778 return;4779 return;
4779 }4780 }
@@ -4785,7 +4786,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) {
4785 await updateWorldInfoList();4786 await updateWorldInfoList();
4786 $('#character_world').val(bookName).trigger('change');4787 $('#character_world').val(bookName).trigger('change');
47874788
4788 toastr.success(`The world "${bookName}" has been imported and linked to the character successfully.`, 'World/Lorebook imported');4789 toastr.success(t`The world '${bookName}' has been imported and linked to the character successfully.`, t`World/Lorebook imported`);
47894790
4790 const newIndex = world_names.indexOf(bookName);4791 const newIndex = world_names.indexOf(bookName);
4791 if (newIndex >= 0) {4792 if (newIndex >= 0) {
@@ -4813,9 +4814,9 @@ export function onWorldInfoChange(args, text) {
4813 if (selected_world_info.includes(name)) {4814 if (selected_world_info.includes(name)) {
4814 selected_world_info.splice(selected_world_info.indexOf(name), 1);4815 selected_world_info.splice(selected_world_info.indexOf(name), 1);
4815 wiElement.prop('selected', false);4816 wiElement.prop('selected', false);
4816 if (!silent) toastr.success(`Deactivated world: ${name}`);4817 if (!silent) toastr.success(t`Deactivated world: ${name}`);
4817 } else {4818 } else {
4818 if (!silent) toastr.error(`World was not active: ${name}`);4819 if (!silent) toastr.error(t`World was not active: ${name}`);
4819 }4820 }
4820 break;4821 break;
4821 }4822 }
@@ -4823,11 +4824,11 @@ export function onWorldInfoChange(args, text) {
4823 if (selected_world_info.includes(name)) {4824 if (selected_world_info.includes(name)) {
4824 selected_world_info.splice(selected_world_info.indexOf(name), 1);4825 selected_world_info.splice(selected_world_info.indexOf(name), 1);
4825 wiElement.prop('selected', false);4826 wiElement.prop('selected', false);
4826 if (!silent) toastr.success(`Deactivated world: ${name}`);4827 if (!silent) toastr.success(t`Deactivated world: ${name}`);
4827 } else {4828 } else {
4828 selected_world_info.push(name);4829 selected_world_info.push(name);
4829 wiElement.prop('selected', true);4830 wiElement.prop('selected', true);
4830 if (!silent) toastr.success(`Activated world: ${name}`);4831 if (!silent) toastr.success(t`Activated world: ${name}`);
4831 }4832 }
4832 break;4833 break;
4833 }4834 }
@@ -4835,16 +4836,16 @@ export function onWorldInfoChange(args, text) {
4835 default: {4836 default: {
4836 selected_world_info.push(name);4837 selected_world_info.push(name);
4837 wiElement.prop('selected', true);4838 wiElement.prop('selected', true);
4838 if (!silent) toastr.success(`Activated world: ${name}`);4839 if (!silent) toastr.success(t`Activated world: ${name}`);
4839 }4840 }
4840 }4841 }
4841 } else {4842 } else {
4842 if (!silent) toastr.error(`No world found named: ${worldName}`);4843 if (!silent) toastr.error(t`No world found named: ${worldName}`);
4843 }4844 }
4844 });4845 });
4845 $('#world_info').trigger('change');4846 $('#world_info').trigger('change');
4846 } else { // if no args, unset all worlds4847 } else { // if no args, unset all worlds
4847 if (!silent) toastr.success('Deactivated all worlds');4848 if (!silent) toastr.success(t`Deactivated all worlds`);
4848 selected_world_info = [];4849 selected_world_info = [];
4849 $('#world_info').val(null).trigger('change');4850 $('#world_info').val(null).trigger('change');
4850 }4851 }
@@ -4860,7 +4861,7 @@ export function onWorldInfoChange(args, text) {
4860 } else {4861 } else {
4861 const wiElement = getWIElement(existingWorldName);4862 const wiElement = getWIElement(existingWorldName);
4862 wiElement.prop('selected', false);4863 wiElement.prop('selected', false);
4863 toastr.error(`The world with ${existingWorldName} is invalid or corrupted.`);4864 toastr.error(t`The world with ${existingWorldName} is invalid or corrupted.`);
4864 }4865 }
4865 });4866 });
4866 }4867 }
@@ -4892,7 +4893,7 @@ export async function importWorldInfo(file) {
4892 }4893 }
48934894
4894 if (jsonData === undefined || jsonData === null) {4895 if (jsonData === undefined || jsonData === null) {
4895 toastr.error(`File is not valid: ${file.name}`);4896 toastr.error(t`File is not valid: ${file.name}`);
4896 return;4897 return;
4897 }4898 }
48984899
@@ -5038,7 +5039,7 @@ jQuery(() => {
50385039
5039 $('#world_create_button').on('click', async () => {5040 $('#world_create_button').on('click', async () => {
5040 const tempName = getFreeWorldName();5041 const tempName = getFreeWorldName();
5041 const finalName = await Popup.show.input('Create a new World Info', 'Enter a name for the new file:', tempName);5042 const finalName = await Popup.show.input(t`Create a new World Info`, t`Enter a name for the new file:`, tempName);
50425043
5043 if (finalName) {5044 if (finalName) {
5044 await createNewWorldInfo(finalName, { interactive: true });5045 await createNewWorldInfo(finalName, { interactive: true });
public/style.css+12 -0
@@ -5735,3 +5735,15 @@ body:not(.movingUI) .drawer-content.maximized {
5735 }5735 }
57365736
5737}5737}
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}