Merge branch 'parser-followup-2' of https://github.com/LenAnderson/SillyTavern into parser-followup-2
This commit is contained in:
commit
83ba31ba06
|
@ -209,20 +209,20 @@
|
|||
opacity: 1;
|
||||
}
|
||||
|
||||
.tag_as_folder {
|
||||
.tag_as_folder.right_menu_button {
|
||||
filter: brightness(75%) saturate(0.6);
|
||||
}
|
||||
|
||||
.tag_as_folder:hover,
|
||||
.tag_as_folder.flash {
|
||||
filter: brightness(150%) saturate(0.6) !important;
|
||||
.tag_as_folder.right_menu_button:hover,
|
||||
.tag_as_folder.right_menu_button.flash {
|
||||
filter: brightness(150%) saturate(0.6);
|
||||
}
|
||||
|
||||
.tag_as_folder.no_folder {
|
||||
.tag_as_folder.right_menu_button.no_folder {
|
||||
filter: brightness(25%) saturate(0.25);
|
||||
}
|
||||
|
||||
.tag_as_folder .tag_folder_indicator {
|
||||
.tag_as_folder.right_menu_button .tag_folder_indicator {
|
||||
position: absolute;
|
||||
top: calc(var(--mainFontSize) * -0.5);
|
||||
right: calc(var(--mainFontSize) * -0.5);
|
||||
|
|
|
@ -1544,7 +1544,7 @@
|
|||
<h4 class="wide100p textAlignCenter">
|
||||
<label>
|
||||
<span data-i18n="Grammar String">Grammar String</span>
|
||||
<div class="margin5 fa-solid fa-circle-info opacity50p " data-i18n="[title]GNBF or ENBF, depends on the backend in use. If you're using this you should know which." title="GNBF or ENBF, depends on the backend in use. If you're using this you should know which."></div>
|
||||
<div class="margin5 fa-solid fa-circle-info opacity50p " data-i18n="[title]GBNF or EBNF, depends on the backend in use. If you're using this you should know which." title="GBNF or EBNF, depends on the backend in use. If you're using this you should know which."></div>
|
||||
<a href="https://github.com/ggerganov/llama.cpp/blob/master/grammars/README.md" target="_blank">
|
||||
<small>
|
||||
<div class="fa-solid fa-up-right-from-square note-link-span"></div>
|
||||
|
@ -3069,7 +3069,11 @@
|
|||
</div>
|
||||
<label class="checkbox_label" title="Add Chat Start and Example Separator to a list of stopping strings." data-i18n="[title]Add Chat Start and Example Separator to a list of stopping strings.">
|
||||
<input id="context_use_stop_strings" type="checkbox" />
|
||||
<small data-i18n="Use as Stop Strings">Use as Stop Strings</small>
|
||||
<small data-i18n="Separators as Stop Strings">Separators as Stop Strings</small>
|
||||
</label>
|
||||
<label class="checkbox_label" title="Add Character and User names to a list of stopping strings." data-i18n="[title]Add Character and User names to a list of stopping strings.">
|
||||
<input id="context_names_as_stop_strings" type="checkbox" />
|
||||
<small data-i18n="Names as Stop Strings">Names as Stop Strings</small>
|
||||
</label>
|
||||
<label class="checkbox_label" title="Includes Post-History Instructions at the end of the prompt, if defined in the character card AND ''Prefer Char. Instructions'' is enabled. THIS IS NOT RECOMMENDED FOR TEXT COMPLETION MODELS, CAN LEAD TO BAD OUTPUT." data-i18n="[title]context_allow_post_history_instructions">
|
||||
<input id="context_allow_jailbreak" type="checkbox" />
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "مخطط جيسون",
|
||||
"Type in the desired JSON schema": "اكتب مخطط JSON المطلوب",
|
||||
"Grammar String": "سلسلة القواعد",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "يعتمد GNBF أو ENBF على الواجهة الخلفية المستخدمة. إذا كنت تستخدم هذا يجب أن تعرف أي.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "يعتمد GBNF أو EBNF على الواجهة الخلفية المستخدمة. إذا كنت تستخدم هذا يجب أن تعرف أي.",
|
||||
"Top P & Min P": "أعلى ع وأدنى ص",
|
||||
"Load default order": "تحميل الترتيب الافتراضي",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp فقط. تحديد ترتيب أخذ العينات. إذا لم يكن وضع Mirostat 0، فسيتم تجاهل ترتيب أخذ العينات.",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "JSON-Schema",
|
||||
"Type in the desired JSON schema": "Geben Sie das gewünschte JSON-Schema ein",
|
||||
"Grammar String": "Grammatikzeichenfolge",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF oder ENBF, hängt vom verwendeten Backend ab. Wenn Sie dieses verwenden, sollten Sie wissen, welches.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF oder EBNF, hängt vom verwendeten Backend ab. Wenn Sie dieses verwenden, sollten Sie wissen, welches.",
|
||||
"Top P & Min P": "Top P und Min P",
|
||||
"Load default order": "Standardreihenfolge laden",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "Nur llama.cpp. Bestimmt die Reihenfolge der Sampler. Wenn der Mirostat-Modus nicht 0 ist, wird die Sampler-Reihenfolge ignoriert.",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "Esquema JSON",
|
||||
"Type in the desired JSON schema": "Escriba el esquema JSON deseado",
|
||||
"Grammar String": "Cadena de gramática",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF o ENBF, depende del backend en uso. Si estás usando esto, debes saber cuál.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF o EBNF, depende del backend en uso. Si estás usando esto, debes saber cuál.",
|
||||
"Top P & Min P": "P superior y P mínima",
|
||||
"Load default order": "Cargar orden predeterminado",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp únicamente. Determina el orden de los muestreadores. Si el modo Mirostat no es 0, se ignora el orden de las muestras.",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "Schéma JSON",
|
||||
"Type in the desired JSON schema": "Tapez le schéma JSON souhaité",
|
||||
"Grammar String": "Chaîne de grammaire",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF ou ENBF dépend du backend utilisé. Si vous l'utilisez, vous devez savoir lequel.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF ou EBNF dépend du backend utilisé. Si vous l'utilisez, vous devez savoir lequel.",
|
||||
"Top P & Min P": "P supérieur et P minimal",
|
||||
"Load default order": "Charger l'ordre par défaut",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "lama.cpp uniquement. Détermine l’ordre des échantillonneurs. Si le mode Mirostat n'est pas 0, l'ordre de l'échantillonneur est ignoré.",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "JSON kerfi",
|
||||
"Type in the desired JSON schema": "Sláðu inn æskilegt JSON skema",
|
||||
"Grammar String": "Málfræðistrengur",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF eða ENBF, fer eftir bakendanum sem er í notkun. Ef þú ert að nota þetta ættir þú að vita hvaða.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF eða EBNF, fer eftir bakendanum sem er í notkun. Ef þú ert að nota þetta ættir þú að vita hvaða.",
|
||||
"Top P & Min P": "Efstu P & Min P",
|
||||
"Load default order": "Hlaða sjálfgefna röð",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp eingöngu. Ákveður röð sýnataka. Ef Mirostat hamur er ekki 0, er röð sýnatöku hunsuð.",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "Schema JSON",
|
||||
"Type in the desired JSON schema": "Digita lo schema JSON desiderato",
|
||||
"Grammar String": "Stringa grammaticale",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF o ENBF, dipende dal backend in uso. Se stai usando questo dovresti sapere quale.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF o EBNF, dipende dal backend in uso. Se stai usando questo dovresti sapere quale.",
|
||||
"Top P & Min P": "P massimo e P minimo",
|
||||
"Load default order": "Carica ordine predefinito",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "Solo lama.cpp. Determina l'ordine dei campionatori. Se la modalità Mirostat non è 0, l'ordine del campionatore viene ignorato.",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "JSONスキーマ",
|
||||
"Type in the desired JSON schema": "希望するJSONスキーマを入力します",
|
||||
"Grammar String": "文法文字列",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF または ENBF は、使用するバックエンドによって異なります。これを使用する場合は、どちらであるかを知っておく必要があります。",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF または EBNF は、使用するバックエンドによって異なります。これを使用する場合は、どちらであるかを知っておく必要があります。",
|
||||
"Top P & Min P": "トップPと最小P",
|
||||
"Load default order": "デフォルトの順序を読み込む",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp のみ。サンプラーの順序を決定します。Mirostat モードが 0 でない場合、サンプラーの順序は無視されます。",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "JSON 스키마",
|
||||
"Type in the desired JSON schema": "원하는 JSON 스키마를 입력하세요.",
|
||||
"Grammar String": "문법 문자열",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF 또는 ENBF는 사용 중인 백엔드에 따라 다릅니다. 이것을 사용한다면 어느 것이 무엇인지 알아야합니다.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 또는 EBNF는 사용 중인 백엔드에 따라 다릅니다. 이것을 사용한다면 어느 것이 무엇인지 알아야합니다.",
|
||||
"Top P & Min P": "상위 P 및 최소 P",
|
||||
"Load default order": "기본 순서로 로드",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp만 가능합니다. 샘플러의 순서를 결정합니다. Mirostat 모드가 0이 아닌 경우 샘플러 순서는 무시됩니다.",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "JSON-schema",
|
||||
"Type in the desired JSON schema": "Typ het gewenste JSON-schema",
|
||||
"Grammar String": "Grammaticareeks",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF of ENBF, hangt af van de gebruikte backend. Als u dit gebruikt, moet u weten welke.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF of EBNF, hangt af van de gebruikte backend. Als u dit gebruikt, moet u weten welke.",
|
||||
"Top P & Min P": "Top P & Min P",
|
||||
"Load default order": "Standaardvolgorde laden",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "alleen lama.cpp. Bepaalt de volgorde van de samplers. Als de Mirostat-modus niet 0 is, wordt de samplervolgorde genegeerd.",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "Esquema JSON",
|
||||
"Type in the desired JSON schema": "Digite o esquema JSON desejado",
|
||||
"Grammar String": "Cadeia de Gramática",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF ou ENBF, depende do backend em uso. Se você estiver usando isso, você deve saber qual.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF ou EBNF, depende do backend em uso. Se você estiver usando isso, você deve saber qual.",
|
||||
"Top P & Min P": "P superior e P mínimo",
|
||||
"Load default order": "Carregar ordem padrão",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "apenas lhama.cpp. Determina a ordem dos amostradores. Se o modo Mirostat não for 0, a ordem do amostrador será ignorada.",
|
||||
|
|
|
@ -978,7 +978,7 @@
|
|||
"char_import_6": "Прямая ссылка на PNG-файл (чтобы узнать список разрешённых хостов, загляните в",
|
||||
"char_import_7": ")",
|
||||
"Grammar String": "Грамматика",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF или ENBF, зависит от бэкенда. Если вы это используете, то, скорее всего, сами знаете, какой именно.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF или EBNF, зависит от бэкенда. Если вы это используете, то, скорее всего, сами знаете, какой именно.",
|
||||
"Account": "Аккаунт",
|
||||
"Hi,": "Привет,",
|
||||
"To enable multi-account features, restart the SillyTavern server with": "Чтобы активировать систему аккаунтов, перезапустите SillyTavern, выставив",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "Схема JSON",
|
||||
"Type in the desired JSON schema": "Введіть потрібну схему JSON",
|
||||
"Grammar String": "Граматичний рядок",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF або ENBF, залежить від серверної частини, яка використовується. Якщо ви використовуєте це, ви повинні знати, який.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF або EBNF, залежить від серверної частини, яка використовується. Якщо ви використовуєте це, ви повинні знати, який.",
|
||||
"Top P & Min P": "Верхній P & Min P",
|
||||
"Load default order": "Завантажити типовий порядок",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "лише llama.cpp. Визначає порядок пробовідбірників. Якщо режим Mirostat не 0, порядок вибірки ігнорується.",
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
"JSON Schema": "Lược đồ JSON",
|
||||
"Type in the desired JSON schema": "Nhập lược đồ JSON mong muốn",
|
||||
"Grammar String": "Chuỗi ngữ pháp",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF hoặc ENBF, tùy thuộc vào backend đang sử dụng. Nếu bạn đang sử dụng cái này, bạn nên biết cái nào.",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF hoặc EBNF, tùy thuộc vào backend đang sử dụng. Nếu bạn đang sử dụng cái này, bạn nên biết cái nào.",
|
||||
"Top P & Min P": "P & P tối thiểu hàng đầu",
|
||||
"Load default order": "Tải thứ tự mặc định",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "chỉ llama.cpp. Xác định thứ tự lấy mẫu. Nếu chế độ Mirostat khác 0, thứ tự lấy mẫu sẽ bị bỏ qua.",
|
||||
|
|
|
@ -208,7 +208,7 @@
|
|||
"JSON Schema": "JSON 结构",
|
||||
"Type in the desired JSON schema": "输入所需的 JSON 结构",
|
||||
"Grammar String": "语法字符串",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF 或 ENBF,取决于使用的后端。如果您使用这个,您应该知道该用哪一个。",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 或 EBNF,取决于使用的后端。如果您使用这个,您应该知道该用哪一个。",
|
||||
"Top P & Min P": "Top P 和 Min P",
|
||||
"Load default order": "加载默认顺序",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "仅限 llama.cpp。确定采样器的顺序。如果 Mirostat 模式不为 0,则忽略采样器顺序。",
|
||||
|
@ -443,7 +443,9 @@
|
|||
"Example Separator": "示例分隔符",
|
||||
"Chat Start": "聊天开始",
|
||||
"Add Chat Start and Example Separator to a list of stopping strings.": "将聊天开始和示例分隔符添加到停止字符串列表中。",
|
||||
"Use as Stop Strings": "用作停止字符串",
|
||||
"Separators as Stop Strings": "分隔符作为终止字符串",
|
||||
"Add Character and User names to a list of stopping strings.": "将角色和用户名添加到停止字符串列表中。",
|
||||
"Names as Stop Strings": "名称作为终止字符串",
|
||||
"context_allow_post_history_instructions": "如果在角色卡中定义并且启用了“首选角色卡说明”,则在提示末尾包含后历史说明。\n不建议在文本补全模型中使用此功能,否则会导致输出错误。",
|
||||
"Allow Post-History Instructions": "允许后历史说明",
|
||||
"Context Order": "上下文顺序",
|
||||
|
|
|
@ -208,7 +208,7 @@
|
|||
"JSON Schema": "JSON 結構",
|
||||
"Type in the desired JSON schema": "輸入所需的 JSON 結構",
|
||||
"Grammar String": "語法字串",
|
||||
"GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF 或 ENBF,取決於所使用的後端。如果您使用此功能,應該知道是哪一種",
|
||||
"GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 或 EBNF,取決於所使用的後端。如果您使用此功能,應該知道是哪一種",
|
||||
"Top P & Min P": "Top P 和 Min P",
|
||||
"Load default order": "載入預設順序",
|
||||
"llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "僅適用於 llama.cpp。決定取樣器的順序。如果 Mirostat 模式不為 0,則忽略取樣器順序。",
|
||||
|
|
208
public/script.js
208
public/script.js
|
@ -227,7 +227,7 @@ import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay
|
|||
import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels } from './scripts/textgen-models.js';
|
||||
import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId } from './scripts/chats.js';
|
||||
import { initPresetManager } from './scripts/preset-manager.js';
|
||||
import { MacrosParser, evaluateMacros } from './scripts/macros.js';
|
||||
import { MacrosParser, evaluateMacros, getLastMessageId } from './scripts/macros.js';
|
||||
import { currentUser, setUserControls } from './scripts/user.js';
|
||||
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js';
|
||||
import { renderTemplate, renderTemplateAsync } from './scripts/templates.js';
|
||||
|
@ -439,6 +439,7 @@ export const event_types = {
|
|||
GROUP_CHAT_CREATED: 'group_chat_created',
|
||||
GENERATE_BEFORE_COMBINE_PROMPTS: 'generate_before_combine_prompts',
|
||||
GENERATE_AFTER_COMBINE_PROMPTS: 'generate_after_combine_prompts',
|
||||
GENERATE_AFTER_DATA: 'generate_after_data',
|
||||
GROUP_MEMBER_DRAFTED: 'group_member_drafted',
|
||||
WORLD_INFO_ACTIVATED: 'world_info_activated',
|
||||
TEXT_COMPLETION_SETTINGS_READY: 'text_completion_settings_ready',
|
||||
|
@ -1720,16 +1721,24 @@ export async function replaceCurrentChat() {
|
|||
}
|
||||
|
||||
export function showMoreMessages() {
|
||||
let messageId = Number($('#chat').children('.mes').first().attr('mesid'));
|
||||
const firstDisplayedMesId = $('#chat').children('.mes').first().attr('mesid');
|
||||
let messageId = Number(firstDisplayedMesId);
|
||||
let count = power_user.chat_truncation || Number.MAX_SAFE_INTEGER;
|
||||
|
||||
// If there are no messages displayed, or the message somehow has no mesid, we default to one higher than last message id,
|
||||
// so the first "new" message being shown will be the last available message
|
||||
if (isNaN(messageId)) {
|
||||
messageId = getLastMessageId() + 1;
|
||||
}
|
||||
|
||||
console.debug('Inserting messages before', messageId, 'count', count, 'chat length', chat.length);
|
||||
const prevHeight = $('#chat').prop('scrollHeight');
|
||||
|
||||
while (messageId > 0 && count > 0) {
|
||||
let newMessageId = messageId - 1;
|
||||
addOneMessage(chat[newMessageId], { insertBefore: messageId >= chat.length ? null : messageId, scroll: false, forceId: newMessageId });
|
||||
count--;
|
||||
messageId--;
|
||||
addOneMessage(chat[messageId], { insertBefore: messageId + 1, scroll: false, forceId: messageId });
|
||||
}
|
||||
|
||||
if (messageId == 0) {
|
||||
|
@ -2470,26 +2479,30 @@ export function substituteParams(content, _name1, _name2, _original, _group, _re
|
|||
* @returns {string[]} Array of stopping strings
|
||||
*/
|
||||
export function getStoppingStrings(isImpersonate, isContinue) {
|
||||
const charString = `\n${name2}:`;
|
||||
const userString = `\n${name1}:`;
|
||||
const result = isImpersonate ? [charString] : [userString];
|
||||
const result = [];
|
||||
|
||||
result.push(userString);
|
||||
if (power_user.context.names_as_stop_strings) {
|
||||
const charString = `\n${name2}:`;
|
||||
const userString = `\n${name1}:`;
|
||||
result.push(isImpersonate ? charString : userString);
|
||||
|
||||
if (isContinue && Array.isArray(chat) && chat[chat.length - 1]?.is_user) {
|
||||
result.push(charString);
|
||||
}
|
||||
result.push(userString);
|
||||
|
||||
// Add other group members as the stopping strings
|
||||
if (selected_group) {
|
||||
const group = groups.find(x => x.id === selected_group);
|
||||
if (isContinue && Array.isArray(chat) && chat[chat.length - 1]?.is_user) {
|
||||
result.push(charString);
|
||||
}
|
||||
|
||||
if (group && Array.isArray(group.members)) {
|
||||
const names = group.members
|
||||
.map(x => characters.find(y => y.avatar == x))
|
||||
.filter(x => x && x.name && x.name !== name2)
|
||||
.map(x => `\n${x.name}:`);
|
||||
result.push(...names);
|
||||
// Add other group members as the stopping strings
|
||||
if (selected_group) {
|
||||
const group = groups.find(x => x.id === selected_group);
|
||||
|
||||
if (group && Array.isArray(group.members)) {
|
||||
const names = group.members
|
||||
.map(x => characters.find(y => y.avatar == x))
|
||||
.filter(x => x && x.name && x.name !== name2)
|
||||
.map(x => `\n${x.name}:`);
|
||||
result.push(...names);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4211,6 +4224,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
|||
}
|
||||
}
|
||||
|
||||
await eventSource.emit(event_types.GENERATE_AFTER_DATA, generate_data);
|
||||
|
||||
if (dryRun) {
|
||||
generatedPromptCache = '';
|
||||
return Promise.resolve();
|
||||
|
@ -5074,7 +5089,7 @@ function setInContextMessages(lastmsg, type) {
|
|||
* @param {object} data Generation data
|
||||
* @returns {Promise<object>} Response data from the API
|
||||
*/
|
||||
async function sendGenerationRequest(type, data) {
|
||||
export async function sendGenerationRequest(type, data) {
|
||||
if (main_api === 'openai') {
|
||||
return await sendOpenAIRequest(type, data.prompt, abortController.signal);
|
||||
}
|
||||
|
@ -5106,7 +5121,7 @@ async function sendGenerationRequest(type, data) {
|
|||
* @param {object} data Generation data
|
||||
* @returns {Promise<any>} Streaming generator
|
||||
*/
|
||||
async function sendStreamingRequest(type, data) {
|
||||
export async function sendStreamingRequest(type, data) {
|
||||
if (abortController?.signal?.aborted) {
|
||||
throw new Error('Generation was aborted.');
|
||||
}
|
||||
|
@ -7917,6 +7932,8 @@ window['SillyTavern'].getContext = function () {
|
|||
eventTypes: event_types,
|
||||
addOneMessage: addOneMessage,
|
||||
generate: Generate,
|
||||
sendStreamingRequest: sendStreamingRequest,
|
||||
sendGenerationRequest: sendGenerationRequest,
|
||||
stopGeneration: stopGeneration,
|
||||
getTokenCount: getTokenCount,
|
||||
extensionPrompts: extension_prompts,
|
||||
|
@ -8310,6 +8327,7 @@ const swipe_right = () => {
|
|||
};
|
||||
|
||||
const CONNECT_API_MAP = {
|
||||
// Default APIs not contined inside text gen / chat gen
|
||||
'kobold': {
|
||||
selected: 'kobold',
|
||||
button: '#api_button',
|
||||
|
@ -8321,153 +8339,49 @@ const CONNECT_API_MAP = {
|
|||
selected: 'novel',
|
||||
button: '#api_button_novel',
|
||||
},
|
||||
'ooba': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.OOBA,
|
||||
},
|
||||
'tabby': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.TABBY,
|
||||
},
|
||||
'llamacpp': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.LLAMACPP,
|
||||
},
|
||||
'ollama': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.OLLAMA,
|
||||
},
|
||||
'mancer': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.MANCER,
|
||||
},
|
||||
'vllm': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.VLLM,
|
||||
},
|
||||
'aphrodite': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.APHRODITE,
|
||||
},
|
||||
'koboldcpp': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.KOBOLDCPP,
|
||||
},
|
||||
// KoboldCpp alias
|
||||
'kcpp': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.KOBOLDCPP,
|
||||
},
|
||||
'togetherai': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.TOGETHERAI,
|
||||
},
|
||||
'openai': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.OPENAI,
|
||||
},
|
||||
// OpenAI alias
|
||||
'oai': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.OPENAI,
|
||||
},
|
||||
'claude': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.CLAUDE,
|
||||
},
|
||||
'windowai': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.WINDOWAI,
|
||||
},
|
||||
// OpenRouter special naming, to differentiate between chat comp and text comp
|
||||
'openrouter': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.OPENROUTER,
|
||||
},
|
||||
'scale': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.SCALE,
|
||||
},
|
||||
'ai21': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.AI21,
|
||||
},
|
||||
'makersuite': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.MAKERSUITE,
|
||||
},
|
||||
'mistralai': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.MISTRALAI,
|
||||
},
|
||||
'custom': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.CUSTOM,
|
||||
},
|
||||
'cohere': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.COHERE,
|
||||
},
|
||||
'perplexity': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.PERPLEXITY,
|
||||
},
|
||||
'groq': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.GROQ,
|
||||
},
|
||||
'01ai': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.ZEROONEAI,
|
||||
},
|
||||
'infermaticai': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.INFERMATICAI,
|
||||
},
|
||||
'dreamgen': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.DREAMGEN,
|
||||
},
|
||||
'openrouter-text': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.OPENROUTER,
|
||||
},
|
||||
'featherless': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.FEATHERLESS,
|
||||
},
|
||||
'huggingface': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.HUGGINGFACE,
|
||||
},
|
||||
};
|
||||
|
||||
// Fill connections map from textgen_types and chat_completion_sources
|
||||
for (const textGenType of Object.values(textgen_types)) {
|
||||
if (CONNECT_API_MAP[textGenType]) continue;
|
||||
CONNECT_API_MAP[textGenType] = {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textGenType,
|
||||
};
|
||||
}
|
||||
for (const chatCompletionSource of Object.values(chat_completion_sources)) {
|
||||
if (CONNECT_API_MAP[chatCompletionSource]) continue;
|
||||
CONNECT_API_MAP[chatCompletionSource] = {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chatCompletionSource,
|
||||
};
|
||||
}
|
||||
|
||||
async function selectContextCallback(_, name) {
|
||||
if (!name) {
|
||||
return power_user.context.preset;
|
||||
|
@ -8599,7 +8513,7 @@ export async function processDroppedFiles(files, data = new Map()) {
|
|||
|
||||
for (const file of files) {
|
||||
const extension = file.name.split('.').pop().toLowerCase();
|
||||
if (allowedMimeTypes.includes(file.type) || allowedExtensions.includes(extension)) {
|
||||
if (allowedMimeTypes.some(x => file.type.startsWith(x)) || allowedExtensions.includes(extension)) {
|
||||
const preservedName = data instanceof Map && data.get(file);
|
||||
await importCharacter(file, preservedName);
|
||||
} else {
|
||||
|
|
|
@ -101,6 +101,21 @@ const showPopupHelper = {
|
|||
if (typeof result === 'string' || typeof result === 'boolean') throw new Error(`Invalid popup result. CONFIRM popups only support numbers, or null. Result: ${result}`);
|
||||
return result;
|
||||
},
|
||||
/**
|
||||
* Asynchronously displays a text popup with the given header and text, returning the clicked result button value.
|
||||
*
|
||||
* @param {string?} header - The header text for the popup.
|
||||
* @param {string?} text - The main text for the popup.
|
||||
* @param {PopupOptions} [popupOptions={}] - Options for the popup.
|
||||
* @return {Promise<POPUP_RESULT>} A Promise that resolves with the result of the user's interaction.
|
||||
*/
|
||||
text: async (header, text, popupOptions = {}) => {
|
||||
const content = PopupUtils.BuildTextWithHeader(header, text);
|
||||
const popup = new Popup(content, POPUP_TYPE.TEXT, null, popupOptions);
|
||||
const result = await popup.show();
|
||||
if (typeof result === 'string' || typeof result === 'boolean') throw new Error(`Invalid popup result. TEXT popups only support numbers, or null. Result: ${result}`);
|
||||
return result;
|
||||
},
|
||||
};
|
||||
|
||||
export class Popup {
|
||||
|
@ -511,14 +526,14 @@ export class Popup {
|
|||
|
||||
return this.#promise;
|
||||
}
|
||||
completeAffirmative() {
|
||||
return this.complete(POPUP_RESULT.AFFIRMATIVE);
|
||||
async completeAffirmative() {
|
||||
return await this.complete(POPUP_RESULT.AFFIRMATIVE);
|
||||
}
|
||||
completeNegative() {
|
||||
return this.complete(POPUP_RESULT.NEGATIVE);
|
||||
async completeNegative() {
|
||||
return await this.complete(POPUP_RESULT.NEGATIVE);
|
||||
}
|
||||
completeCancelled() {
|
||||
return this.complete(POPUP_RESULT.CANCELLED);
|
||||
async completeCancelled() {
|
||||
return await this.complete(POPUP_RESULT.CANCELLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -242,6 +242,7 @@ let power_user = {
|
|||
example_separator: defaultExampleSeparator,
|
||||
use_stop_strings: true,
|
||||
allow_jailbreak: false,
|
||||
names_as_stop_strings: true,
|
||||
},
|
||||
|
||||
personas: {},
|
||||
|
@ -348,6 +349,7 @@ const contextControls = [
|
|||
{ id: 'context_chat_start', property: 'chat_start', isCheckbox: false, isGlobalSetting: false },
|
||||
{ id: 'context_use_stop_strings', property: 'use_stop_strings', isCheckbox: true, isGlobalSetting: false, defaultValue: false },
|
||||
{ id: 'context_allow_jailbreak', property: 'allow_jailbreak', isCheckbox: true, isGlobalSetting: false, defaultValue: false },
|
||||
{ id: 'context_names_as_stop_strings', property: 'names_as_stop_strings', isCheckbox: true, isGlobalSetting: false, defaultValue: true },
|
||||
|
||||
// Existing power user settings
|
||||
{ id: 'always-force-name2-checkbox', property: 'always_force_name2', isCheckbox: true, isGlobalSetting: true, defaultValue: true },
|
||||
|
|
|
@ -158,12 +158,12 @@ async function showSamplerSelectPopup() {
|
|||
<div class="flex-container justifyCenter">
|
||||
<h3>Sampler Select</h3>
|
||||
<div class="flex-container alignItemsBaseline">
|
||||
<div id="resetSelectedSamplers" class="menu_button menu_button_icon tag_view_create" title="Reset custom sampler selection">
|
||||
<div id="resetSelectedSamplers" class="menu_button menu_button_icon" title="Reset custom sampler selection">
|
||||
<i class="fa-solid fa-recycle"></i>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div class="flex-container alignItemsBaseline">
|
||||
<div class="menu_button menu_button_icon tag_view_create" title="Create a new sampler">
|
||||
<div class="menu_button menu_button_icon" title="Create a new sampler">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
<span data-i18n="Create">Create</span>
|
||||
</div>
|
||||
|
|
|
@ -21,7 +21,7 @@ import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
|||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
||||
import { isMobile } from './RossAscends-mods.js';
|
||||
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from './popup.js';
|
||||
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
|
||||
import { debounce_timeout } from './constants.js';
|
||||
import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js';
|
||||
import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
|
@ -1367,27 +1367,8 @@ function makeTagListDraggable(tagContainer) {
|
|||
const id = $(tagElement).attr('id');
|
||||
const tag = tags.find(x => x.id === id);
|
||||
|
||||
// Fix the defined colors, because if there is no color set, they seem to get automatically set to black
|
||||
// based on the color picker after drag&drop, even if there was no color chosen. We just set them back.
|
||||
const color = $(tagElement).find('.tagColorPickerHolder .tag-color').attr('color');
|
||||
const color2 = $(tagElement).find('.tagColorPicker2Holder .tag-color2').attr('color');
|
||||
if (color === '' || color === undefined) {
|
||||
tag.color = '';
|
||||
fixColor('background-color', tag.color);
|
||||
}
|
||||
if (color2 === '' || color2 === undefined) {
|
||||
tag.color2 = '';
|
||||
fixColor('color', tag.color2);
|
||||
}
|
||||
|
||||
// Update the sort order
|
||||
tag.sort_order = i;
|
||||
|
||||
function fixColor(property, color) {
|
||||
$(tagElement).find('.tag_view_name').css(property, color);
|
||||
$(`.tag[id="${id}"]`).css(property, color);
|
||||
$(`.bogus_folder_select[tagid="${id}"] .avatar`).css(property, color);
|
||||
}
|
||||
});
|
||||
|
||||
// If tags were dragged manually, we have to disable auto sorting
|
||||
|
@ -1455,18 +1436,28 @@ async function onTagRestoreFileSelect(e) {
|
|||
const data = await parseJsonFile(file);
|
||||
|
||||
if (!data) {
|
||||
toastr.warning('Empty file data', 'Tag restore');
|
||||
toastr.warning('Empty file data', 'Tag Restore');
|
||||
console.log('Tag restore: File data empty.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.tags || !data.tag_map || !Array.isArray(data.tags) || typeof data.tag_map !== 'object') {
|
||||
toastr.warning('Invalid file format', 'Tag restore');
|
||||
toastr.warning('Invalid file format', 'Tag Restore');
|
||||
console.log('Tag restore: Invalid file format.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Prompt user if they want to overwrite existing tags
|
||||
let overwrite = false;
|
||||
if (tags.length > 0) {
|
||||
const result = await Popup.show.confirm('Tag Restore', 'You have existing tags. If the backup contains any of those tags, do you want the backup to overwrite their settings (Name, color, folder state, etc)?',
|
||||
{ okButton: 'Overwrite', cancelButton: 'Keep Existing' });
|
||||
overwrite = result === POPUP_RESULT.AFFIRMATIVE;
|
||||
}
|
||||
|
||||
const warnings = [];
|
||||
/** @type {Map<string, string>} Map import tag ids with existing ids on overwrite */
|
||||
const idToActualTagIdMap = new Map();
|
||||
|
||||
// Import tags
|
||||
for (const tag of data.tags) {
|
||||
|
@ -1475,10 +1466,28 @@ async function onTagRestoreFileSelect(e) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (tags.find(x => x.id === tag.id)) {
|
||||
warnings.push(`Tag with id ${tag.id} already exists.`);
|
||||
// Check against both existing id (direct match) and tag with the same name, which is not allowed.
|
||||
let existingTag = tags.find(x => x.id === tag.id);
|
||||
if (existingTag && !overwrite) {
|
||||
warnings.push(`Tag '${tag.name}' with id ${tag.id} already exists.`);
|
||||
continue;
|
||||
}
|
||||
existingTag = getTag(tag.name);
|
||||
if (existingTag && !overwrite) {
|
||||
warnings.push(`Tag with name '${tag.name}' already exists.`);
|
||||
// Remember the tag id, so we can still import the tag map entries for this
|
||||
idToActualTagIdMap.set(tag.id, existingTag.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (existingTag) {
|
||||
// On overwrite, we remove and re-add the tag
|
||||
removeFromArray(tags, existingTag);
|
||||
// And remember the ID if it was different, so we can update the tag map accordingly
|
||||
if (existingTag.id !== tag.id) {
|
||||
idToActualTagIdMap.set(existingTag.id, tag.id);
|
||||
}
|
||||
}
|
||||
|
||||
tags.push(tag);
|
||||
}
|
||||
|
@ -1497,30 +1506,39 @@ async function onTagRestoreFileSelect(e) {
|
|||
const groupExists = groups.some(x => String(x.id) === String(key));
|
||||
|
||||
if (!characterExists && !groupExists) {
|
||||
warnings.push(`Tag map key ${key} does not exist.`);
|
||||
warnings.push(`Tag map key ${key} does not exist as character or group.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get existing tag ids for this key or empty array.
|
||||
const existingTagIds = tag_map[key] || [];
|
||||
// Merge existing and new tag ids. Remove duplicates.
|
||||
tag_map[key] = existingTagIds.concat(tagIds).filter(onlyUnique);
|
||||
|
||||
// Merge existing and new tag ids. Replace the ones mapped to a new id. Remove duplicates.
|
||||
const combinedTags = existingTagIds.concat(tagIds)
|
||||
.map(tagId => (idToActualTagIdMap.has(tagId)) ? idToActualTagIdMap.get(tagId) : tagId)
|
||||
.filter(onlyUnique);
|
||||
|
||||
// Verify that all tags exist. Remove tags that don't exist.
|
||||
tag_map[key] = tag_map[key].filter(x => tags.some(y => String(y.id) === String(x)));
|
||||
tag_map[key] = combinedTags.filter(tagId => tags.some(y => String(y.id) === String(tagId)));
|
||||
}
|
||||
|
||||
if (warnings.length) {
|
||||
toastr.success('Tags restored with warnings. Check console for details.');
|
||||
toastr.warning('Tags restored with warnings. Check console or click on this message for details.', 'Tag Restore', {
|
||||
timeOut: toastr.options.timeOut * 2, // Display double the time
|
||||
onclick: () => Popup.show.text('Tag Restore Warnings', `<samp class="justifyLeft">${DOMPurify.sanitize(warnings.join('\n'))}<samp>`, { allowVerticalScrolling: true }),
|
||||
});
|
||||
console.warn(`TAG RESTORE REPORT\n====================\n${warnings.join('\n')}`);
|
||||
} else {
|
||||
toastr.success('Tags restored successfully.');
|
||||
toastr.success('Tags restored successfully.', 'Tag Restore');
|
||||
}
|
||||
|
||||
$('#tag_view_restore_input').val('');
|
||||
printCharactersDebounced();
|
||||
saveSettingsDebounced();
|
||||
|
||||
await onViewTagsListClick();
|
||||
// Reprint the tag management popup, without having it to be opened again
|
||||
const tagContainer = $('#tag_view_list .tag_view_list_tags');
|
||||
printViewTagList(tagContainer);
|
||||
}
|
||||
|
||||
function onBackupRestoreClick() {
|
||||
|
@ -1577,7 +1595,7 @@ function appendViewTagToList(list, tag, everything) {
|
|||
|
||||
const primaryColorPicker = $('<toolcool-color-picker></toolcool-color-picker>')
|
||||
.addClass('tag-color')
|
||||
.attr({ id: colorPickerId, color: tag.color || 'rgba(0, 0, 0, 0.3)', 'data-default-color': 'rgba(0, 0, 0, 0.3)' });
|
||||
.attr({ id: colorPickerId, color: tag.color || 'rgba(0, 0, 0, 0.5)', 'data-default-color': 'rgba(0, 0, 0, 0.5)' });
|
||||
|
||||
const secondaryColorPicker = $('<toolcool-color-picker></toolcool-color-picker>')
|
||||
.addClass('tag-color2')
|
||||
|
|
|
@ -3584,7 +3584,7 @@ export async function getSortedEntries() {
|
|||
|
||||
// Parse decorators
|
||||
entries = entries.map((entry) => {
|
||||
const [decorators, content] = parseDecorators(entry.content);
|
||||
const [decorators, content] = parseDecorators(entry.content || '');
|
||||
return { ...entry, decorators, content };
|
||||
});
|
||||
|
||||
|
|
|
@ -470,6 +470,13 @@ kbd {
|
|||
line-height: 1;
|
||||
}
|
||||
|
||||
samp {
|
||||
display: block;
|
||||
font-family: var(--monoFontFamily);
|
||||
white-space: pre-wrap;
|
||||
text-align: start;
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
hr {
|
||||
background-image: linear-gradient(90deg, var(--transparent), var(--SmartThemeBodyColor), var(--transparent));
|
||||
|
|
|
@ -312,6 +312,9 @@ const TOGETHERAI_KEYS = [
|
|||
'top_p',
|
||||
'top_k',
|
||||
'repetition_penalty',
|
||||
'min_p',
|
||||
'presence_penalty',
|
||||
'frequency_penalty',
|
||||
'stream',
|
||||
'stop',
|
||||
];
|
||||
|
|
Loading…
Reference in New Issue