mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-22 23:18:27 +01:00
Merge branch 'staging' of https://github.com/joenunezb/SillyTavern into optimize/improve-search
This commit is contained in:
commit
78c55558af
40
.github/readme-ru_ru.md
vendored
40
.github/readme-ru_ru.md
vendored
@ -229,6 +229,46 @@ SillyTavern сохраняет ключи от ваших API в файле `sec
|
||||
1. Зайдите в файл `config.yaml` и установите `allowKeysExposure` в положение `true`.
|
||||
2. Перезапустите сервер SillyTavern.
|
||||
|
||||
## Аргументы командной строки
|
||||
|
||||
Вы можете передавать аргументы командной строки при запуске сервера SillyTavern, чтобы переопределять настройки из `config.yaml`.
|
||||
|
||||
### Примеры
|
||||
|
||||
```shell
|
||||
node server.js --port 8000 --listen false
|
||||
# или
|
||||
npm run start -- --port 8000 --listen false
|
||||
# или (только на Windows)
|
||||
Start.bat --port 8000 --listen false
|
||||
```
|
||||
|
||||
### Поддерживаемые аргументы
|
||||
|
||||
| Аргумент | Описание | Тип |
|
||||
|-------------------------|----------------------------------------------------------------------------------------------------------------|----------|
|
||||
| `--version` | Показывает номер версии. | boolean |
|
||||
| `--enableIPv6` | Включает IPv6. | boolean |
|
||||
| `--enableIPv4` | Включает IPv4. | boolean |
|
||||
| `--port` | Устанавливает порт, котрый будет использовать SillyTavern. Если не указан, то используется yaml-конфиг 'port'. | number |
|
||||
| `--dnsPreferIPv6` | Отдает предпочтение IPv6 для dns. Если не указан, то используется yaml-конфиг 'preferIPv6'. | boolean |
|
||||
| `--autorun` | Автоматический запуск SillyTavern в браузере. Если не указан, то используется yaml-конфиг 'autorun'. | boolean |
|
||||
| `--autorunHostname` | Имя хоста автозапуска, лучше оставить на 'auto'. | string |
|
||||
| `--autorunPortOverride` | Переопределяет порт для автозапуска. | string |
|
||||
| `--listen` | SillyTavern будет прослушивать все сетевые интерфейсы. Если не указан, то используется yaml-конфиг 'listen'. | boolean |
|
||||
| `--corsProxy` | Включает CORS-прокси. Если не указан, то используется yaml-конфиг 'enableCorsProxy'. | boolean |
|
||||
| `--disableCsrf` | Отключает защиту от CSRF. | boolean |
|
||||
| `--ssl` | Включает SSL. | boolean |
|
||||
| `--certPath` | Путь к файлу c сертификатом. | string |
|
||||
| `--keyPath` | Путь к файлу с закрытым ключом. | string |
|
||||
| `--whitelist` | Включает режим белого списка. | boolean |
|
||||
| `--dataRoot` | Корневой каталог для хранения данных. | string |
|
||||
| `--avoidLocalhost` | Избегает использования 'localhost' для автозапуска в режиме 'auto'. | boolean |
|
||||
| `--basicAuthMode` | Включает простую аутентификацию. | boolean |
|
||||
| `--requestProxyEnabled` | Разрешает использование прокси для исходящих запросов. | boolean |
|
||||
| `--requestProxyUrl` | URL-адрес прокси (протоколы HTTP или SOCKS). | string |
|
||||
| `--requestProxyBypass` | Bypass список прокси (список хостов, разделенных пробелами). | array |
|
||||
|
||||
## Удалённое подключение
|
||||
|
||||
В основном этим пользуются тогда, когда хотят использовать SillyTavern с телефона, запустив сервер SillyTavern на стационарном ПК в той же Wi-Fi-сети.
|
||||
|
@ -230,7 +230,6 @@
|
||||
"show_external_models": false,
|
||||
"assistant_prefill": "",
|
||||
"assistant_impersonation": "",
|
||||
"human_sysprompt_message": "Let's get started. Please generate your response based on the information and instructions provided above.",
|
||||
"claude_use_sysprompt": false,
|
||||
"use_alt_scale": false,
|
||||
"squash_system_messages": false,
|
||||
|
@ -1291,6 +1291,14 @@
|
||||
<input class="neo-range-slider" type="range" id="epsilon_cutoff_textgenerationwebui" name="volume" min="0" max="9" step="0.01">
|
||||
<input class="neo-range-input" type="number" min="0" max="9" step="0.01" data-for="epsilon_cutoff_textgenerationwebui" id="epsilon_cutoff_counter_textgenerationwebui">
|
||||
</div>
|
||||
<div data-tg-type="aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
|
||||
<small>
|
||||
<span data-i18n="Top nsigma">Top nsigma</span>
|
||||
<div class="fa-solid fa-circle-info opacity50p" title="A sampling method that filters logits based on their statistical properties. It keeps tokens within n standard deviations of the maximum logit value, providing a simpler alternative to top-p/top-k sampling while maintaining sampling stability across different temperatures."></div>
|
||||
</small>
|
||||
<input class="neo-range-slider" type="range" id="nsigma_textgenerationwebui" name="volume" min="0" max="5" step="0.01">
|
||||
<input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="nsigma_textgenerationwebui" id="nsigma_counter_textgenerationwebui">
|
||||
</div>
|
||||
<div data-tg-type="ooba,mancer,aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
|
||||
<small>
|
||||
<span data-i18n="Eta Cutoff">Eta Cutoff</span>
|
||||
@ -1334,12 +1342,12 @@
|
||||
<input class="neo-range-slider" type="range" id="presence_pen_textgenerationwebui" name="volume" min="-2" max="2" step="0.01" />
|
||||
<input class="neo-range-input" type="number" min="-2" max="2" step="0.01" data-for="presence_pen_textgenerationwebui" id="presence_pen_counter_textgenerationwebui">
|
||||
</div>
|
||||
<div data-tg-type="ooba" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
|
||||
<div data-tg-type="aphrodite, ooba" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
|
||||
<small data-i18n="No Repeat Ngram Size">No Repeat Ngram Size</small>
|
||||
<input class="neo-range-slider" type="range" id="no_repeat_ngram_size_textgenerationwebui" name="volume" min="0" max="20" step="1">
|
||||
<input class="neo-range-input" type="number" min="0" max="20" step="1" data-for="no_repeat_ngram_size_textgenerationwebui" id="no_repeat_ngram_size_counter_textgenerationwebui">
|
||||
</div>
|
||||
<div data-tg-type="tabby" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
|
||||
<div data-tg-type="tabby, aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
|
||||
<small data-i18n="Skew">Skew</small>
|
||||
<input class="neo-range-slider" type="range" id="skew_textgenerationwebui" name="volume" min="-5" max="5" step="0.01" />
|
||||
<input class="neo-range-input" type="number" min="-5" max="5" step="0.01" data-for="skew_textgenerationwebui" id="skew_counter_textgenerationwebui">
|
||||
@ -1394,7 +1402,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-tg-type="ooba, koboldcpp, tabby, llamacpp" id="dryBlock" class="wide100p">
|
||||
<div data-tg-type="aphrodite, ooba, koboldcpp, tabby, llamacpp" id="dryBlock" class="wide100p">
|
||||
<h4 class="wide100p textAlignCenter" title="DRY penalizes tokens that would extend the end of the input into a sequence that has previously occurred in the input. Set multiplier to 0 to disable." data-i18n="[title]DRY_Repetition_Penalty_desc">
|
||||
<label data-i18n="DRY Repetition Penalty">DRY Repetition Penalty</label>
|
||||
<a href="https://github.com/oobabooga/text-generation-webui/pull/5677" target="_blank">
|
||||
@ -1951,15 +1959,6 @@
|
||||
Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.
|
||||
</span>
|
||||
</div>
|
||||
<div id="claude_human_sysprompt_message_block" class="wide100p">
|
||||
<div class="range-block-title openai_restorable">
|
||||
<span data-i18n="User first message">User first message</span>
|
||||
<div id="claude_human_sysprompt_message_restore" title="Restore User first message" data-i18n="[title]Restore User first message" class="right_menu_button">
|
||||
<div class="fa-solid fa-clock-rotate-left"></div>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="claude_human_sysprompt_textarea" class="text_pole textarea_compact autoSetHeight" rows="2" data-i18n="[placeholder]Human message" placeholder="Human message, instruction, etc. Adds nothing when empty, i.e. requires a new prompt with the role 'user'."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block m-t-1" data-source="openai,openrouter,scale,custom">
|
||||
@ -2805,9 +2804,6 @@
|
||||
<option value="claude-3-haiku-20240307">claude-3-haiku-20240307</option>
|
||||
<option value="claude-2.1">claude-2.1</option>
|
||||
<option value="claude-2.0">claude-2.0</option>
|
||||
<option value="claude-1.3">claude-1.3</option>
|
||||
<option value="claude-instant-1.2">claude-instant-1.2</option>
|
||||
<option value="claude-instant-1.1">claude-instant-1.1</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -2707,8 +2707,7 @@ export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, q
|
||||
quietName: quietName,
|
||||
};
|
||||
originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1;
|
||||
const generateFinished = await Generate('quiet', options);
|
||||
return generateFinished;
|
||||
return await Generate('quiet', options);
|
||||
} finally {
|
||||
if (responseLengthCustomized) {
|
||||
restoreResponseLength(main_api, originalResponseLength);
|
||||
@ -3363,9 +3362,9 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
|
||||
|
||||
let data = {};
|
||||
|
||||
if (api == 'koboldhorde') {
|
||||
if (api === 'koboldhorde') {
|
||||
data = await generateHorde(prompt, generateData, abortController.signal, false);
|
||||
} else if (api == 'openai') {
|
||||
} else if (api === 'openai') {
|
||||
data = await sendOpenAIRequest('quiet', generateData, abortController.signal);
|
||||
} else {
|
||||
const generateUrl = getGenerateUrl(api);
|
||||
@ -3378,13 +3377,15 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw error;
|
||||
throw await response.json();
|
||||
}
|
||||
|
||||
data = await response.json();
|
||||
}
|
||||
|
||||
// should only happen for text completions
|
||||
// other frontend paths do not return data if calling the backend fails,
|
||||
// they throw things instead
|
||||
if (data.error) {
|
||||
throw new Error(data.response);
|
||||
}
|
||||
@ -4436,6 +4437,11 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves itemized prompt bits and calls streaming or non-streaming generation API.
|
||||
* @returns {Promise<void|*|Awaited<*>|String|{fromStream}|string|undefined|Object>}
|
||||
* @throws {Error|object} Error with message text, or Error with response JSON (OAI/Horde), or the actual response JSON (novel|textgenerationwebui|kobold)
|
||||
*/
|
||||
async function finishGenerating() {
|
||||
if (power_user.console_log_prompts) {
|
||||
console.log(generate_data.prompt);
|
||||
@ -4547,6 +4553,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
|
||||
return finishGenerating().then(onSuccess, onError);
|
||||
|
||||
/**
|
||||
* Handles the successful response from the generation API.
|
||||
* @param data
|
||||
* @returns {Promise<String|{fromStream}|*|string|string|void|Awaited<*>|undefined>}
|
||||
* @throws {Error} Throws an error if the response data contains an error message
|
||||
*/
|
||||
async function onSuccess(data) {
|
||||
if (!data) return;
|
||||
|
||||
@ -4556,6 +4568,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
|
||||
let messageChunk = '';
|
||||
|
||||
// if an error was returned in data (textgenwebui), show it and throw it
|
||||
if (data.error) {
|
||||
unblockGeneration(type);
|
||||
generatedPromptCache = '';
|
||||
@ -4670,9 +4683,15 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
return Object.defineProperty(new String(getMessage), 'messageChunk', { value: messageChunk });
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception handler for finishGenerating
|
||||
* @param {Error|object} exception Error or response JSON
|
||||
* @throws {Error|object} Re-throws the exception
|
||||
*/
|
||||
function onError(exception) {
|
||||
// if the response JSON was thrown (novel|textgenerationwebui|kobold), show the error message
|
||||
if (typeof exception?.error?.message === 'string') {
|
||||
toastr.error(exception.error.message, t`Error`, { timeOut: 10000, extendedTimeOut: 20000 });
|
||||
toastr.error(exception.error.message, t`Text generation error`, { timeOut: 10000, extendedTimeOut: 20000 });
|
||||
}
|
||||
|
||||
generatedPromptCache = '';
|
||||
@ -5340,6 +5359,7 @@ function setInContextMessages(lastmsg, type) {
|
||||
* @param {string} type Generation type
|
||||
* @param {object} data Generation data
|
||||
* @returns {Promise<object>} Response data from the API
|
||||
* @throws {Error|object}
|
||||
*/
|
||||
export async function sendGenerationRequest(type, data) {
|
||||
if (main_api === 'openai') {
|
||||
@ -5359,12 +5379,10 @@ export async function sendGenerationRequest(type, data) {
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw error;
|
||||
throw await response.json();
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
return responseData;
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5396,6 +5414,7 @@ export async function sendStreamingRequest(type, data) {
|
||||
* Gets the generation endpoint URL for the specified API.
|
||||
* @param {string} api API name
|
||||
* @returns {string} Generation URL
|
||||
* @throws {Error} If the API is unknown
|
||||
*/
|
||||
function getGenerateUrl(api) {
|
||||
switch (api) {
|
||||
|
@ -65,6 +65,11 @@ const parse_derivation = derivation => (typeof derivation === 'string') ? {
|
||||
} : derivation;
|
||||
|
||||
export async function deriveTemplatesFromChatTemplate(chat_template, hash) {
|
||||
if (chat_template.trim() === '') {
|
||||
console.log('Missing chat template.');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (hash in hash_derivations) {
|
||||
return parse_derivation(hash_derivations[hash]);
|
||||
}
|
||||
|
@ -2373,6 +2373,7 @@ function ensureSelectionExists(setting, selector) {
|
||||
* @param {string} [message] Chat message
|
||||
* @param {function} [callback] Callback function
|
||||
* @returns {Promise<string|undefined>} Image path
|
||||
* @throws {Error} If the prompt or image generation fails
|
||||
*/
|
||||
async function generatePicture(initiator, args, trigger, message, callback) {
|
||||
if (!trigger || trigger.trim().length === 0) {
|
||||
@ -2391,7 +2392,7 @@ async function generatePicture(initiator, args, trigger, message, callback) {
|
||||
trigger = trigger.trim();
|
||||
const generationType = getGenerationType(trigger);
|
||||
const generationTypeKey = Object.keys(generationMode).find(key => generationMode[key] === generationType);
|
||||
console.log(`Generation mode ${generationTypeKey} triggered with "${trigger}"`);
|
||||
console.log(`Image generation mode ${generationTypeKey} triggered with "${trigger}"`);
|
||||
|
||||
const quietPrompt = getQuietPrompt(generationType, trigger);
|
||||
const context = getContext();
|
||||
@ -2428,6 +2429,8 @@ async function generatePicture(initiator, args, trigger, message, callback) {
|
||||
|
||||
try {
|
||||
const combineNegatives = (prefix) => { negativePromptPrefix = combinePrefixes(negativePromptPrefix, prefix); };
|
||||
|
||||
// generate the text prompt for the image
|
||||
const prompt = await getPrompt(generationType, message, trigger, quietPrompt, combineNegatives);
|
||||
console.log('Processed image prompt:', prompt);
|
||||
|
||||
@ -2438,11 +2441,16 @@ async function generatePicture(initiator, args, trigger, message, callback) {
|
||||
args._abortController.addEventListener('abort', stopListener);
|
||||
}
|
||||
|
||||
// generate the image
|
||||
imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback, initiator, abortController.signal);
|
||||
} catch (err) {
|
||||
console.trace(err);
|
||||
toastr.error('SD prompt text generation failed. Reason: ' + err, 'Image Generation');
|
||||
throw new Error('SD prompt text generation failed. Reason: ' + err);
|
||||
// errors here are most likely due to text generation failure
|
||||
// sendGenerationRequest mostly deals with its own errors
|
||||
const reason = err.error?.message || err.message || 'Unknown error';
|
||||
const errorText = 'SD prompt text generation failed. ' + reason;
|
||||
toastr.error(errorText, 'Image Generation');
|
||||
throw new Error(errorText);
|
||||
}
|
||||
finally {
|
||||
$(stopButton).hide();
|
||||
@ -2513,7 +2521,7 @@ function restoreOriginalDimensions(savedParams) {
|
||||
*/
|
||||
async function getPrompt(generationType, message, trigger, quietPrompt, combineNegatives) {
|
||||
let prompt;
|
||||
|
||||
console.log('getPrompt: Generation mode', generationType, 'triggered with', trigger);
|
||||
switch (generationType) {
|
||||
case generationMode.RAW_LAST:
|
||||
prompt = message || getRawLastMessage();
|
||||
@ -2729,7 +2737,7 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP
|
||||
throw new Error('Endpoint did not return image data.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
console.error('Image generation request error: ', err);
|
||||
toastr.error('Image generation failed. Please try again.' + '\n\n' + String(err), 'Image Generation');
|
||||
return;
|
||||
}
|
||||
|
@ -181,6 +181,14 @@ function setContextSizePreview() {
|
||||
}
|
||||
}
|
||||
|
||||
/** Generates text using the Horde API.
|
||||
* @param {string} prompt
|
||||
* @param params
|
||||
* @param signal
|
||||
* @param reportProgress
|
||||
* @returns {Promise<{text: *, workerName: string}>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
async function generateHorde(prompt, params, signal, reportProgress) {
|
||||
validateHordeModel();
|
||||
delete params.prompt;
|
||||
|
@ -99,7 +99,6 @@ const default_wi_format = '{0}';
|
||||
const default_new_chat_prompt = '[Start a new Chat]';
|
||||
const default_new_group_chat_prompt = '[Start a new group chat. Group members: {{group}}]';
|
||||
const default_new_example_chat_prompt = '[Example Chat]';
|
||||
const default_claude_human_sysprompt_message = 'Let\'s get started. Please generate your response based on the information and instructions provided above.';
|
||||
const default_continue_nudge_prompt = '[Continue the following message. Do not include ANY parts of the original message. Use capitalization and punctuation as if your reply is a part of the original message: {{lastChatMessage}}]';
|
||||
const default_bias = 'Default (none)';
|
||||
const default_personality_format = '[{{char}}\'s personality: {{personality}}]';
|
||||
@ -276,7 +275,6 @@ const default_settings = {
|
||||
proxy_password: '',
|
||||
assistant_prefill: '',
|
||||
assistant_impersonation: '',
|
||||
human_sysprompt_message: default_claude_human_sysprompt_message,
|
||||
claude_use_sysprompt: false,
|
||||
use_makersuite_sysprompt: true,
|
||||
use_alt_scale: false,
|
||||
@ -353,7 +351,6 @@ const oai_settings = {
|
||||
proxy_password: '',
|
||||
assistant_prefill: '',
|
||||
assistant_impersonation: '',
|
||||
human_sysprompt_message: default_claude_human_sysprompt_message,
|
||||
claude_use_sysprompt: false,
|
||||
use_makersuite_sysprompt: true,
|
||||
use_alt_scale: false,
|
||||
@ -1313,6 +1310,11 @@ export async function prepareOpenAIMessages({
|
||||
return [chat, promptManager.tokenHandler.counts];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles errors during streaming requests.
|
||||
* @param {Response} response
|
||||
* @param {string} decoded - response text or decoded stream data
|
||||
*/
|
||||
function tryParseStreamingError(response, decoded) {
|
||||
try {
|
||||
const data = JSON.parse(decoded);
|
||||
@ -1324,6 +1326,9 @@ function tryParseStreamingError(response, decoded) {
|
||||
checkQuotaError(data);
|
||||
checkModerationError(data);
|
||||
|
||||
// these do not throw correctly (equiv to Error("[object Object]"))
|
||||
// if trying to fix "[object Object]" displayed to users, start here
|
||||
|
||||
if (data.error) {
|
||||
toastr.error(data.error.message || response.statusText, 'Chat Completion API');
|
||||
throw new Error(data);
|
||||
@ -1339,15 +1344,22 @@ function tryParseStreamingError(response, decoded) {
|
||||
}
|
||||
}
|
||||
|
||||
async function checkQuotaError(data) {
|
||||
const errorText = await renderTemplateAsync('quotaError');
|
||||
|
||||
/**
|
||||
* Checks if the response contains a quota error and displays a popup if it does.
|
||||
* @param data
|
||||
* @returns {void}
|
||||
* @throws {object} - response JSON
|
||||
*/
|
||||
function checkQuotaError(data) {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.quota_error) {
|
||||
callPopup(errorText, 'text');
|
||||
renderTemplateAsync('quotaError').then((html) => Popup.show.text('Quota Error', html));
|
||||
|
||||
// this does not throw correctly (equiv to Error("[object Object]"))
|
||||
// if trying to fix "[object Object]" displayed to users, start here
|
||||
throw new Error(data);
|
||||
}
|
||||
}
|
||||
@ -1766,6 +1778,15 @@ async function sendAltScaleRequest(messages, logit_bias, signal, type) {
|
||||
return data.output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a chat completion request to backend
|
||||
* @param {string} type (impersonate, quiet, continue, etc)
|
||||
* @param {Array} messages
|
||||
* @param {AbortSignal?} signal
|
||||
* @returns {Promise<unknown>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
|
||||
async function sendOpenAIRequest(type, messages, signal) {
|
||||
// Provide default abort signal
|
||||
if (!signal) {
|
||||
@ -1868,7 +1889,6 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
generate_data['top_k'] = Number(oai_settings.top_k_openai);
|
||||
generate_data['claude_use_sysprompt'] = oai_settings.claude_use_sysprompt;
|
||||
generate_data['stop'] = getCustomStoppingStrings(); // Claude shouldn't have limits on stop strings.
|
||||
generate_data['human_sysprompt_message'] = substituteParams(oai_settings.human_sysprompt_message);
|
||||
// Don't add a prefill on quiet gens (summarization) and when using continue prefill.
|
||||
if (!isQuiet && !(isContinue && oai_settings.continue_prefill)) {
|
||||
generate_data['assistant_prefill'] = isImpersonate ? substituteParams(oai_settings.assistant_impersonation) : substituteParams(oai_settings.assistant_prefill);
|
||||
@ -2028,12 +2048,13 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
else {
|
||||
const data = await response.json();
|
||||
|
||||
await checkQuotaError(data);
|
||||
checkQuotaError(data);
|
||||
checkModerationError(data);
|
||||
|
||||
if (data.error) {
|
||||
toastr.error(data.error.message || response.statusText, t`API returned an error`);
|
||||
throw new Error(data);
|
||||
const message = data.error.message || response.statusText || t`Unknown error`;
|
||||
toastr.error(message, t`API returned an error`);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
if (type !== 'quiet') {
|
||||
@ -3005,7 +3026,6 @@ function loadOpenAISettings(data, settings) {
|
||||
oai_settings.proxy_password = settings.proxy_password ?? default_settings.proxy_password;
|
||||
oai_settings.assistant_prefill = settings.assistant_prefill ?? default_settings.assistant_prefill;
|
||||
oai_settings.assistant_impersonation = settings.assistant_impersonation ?? default_settings.assistant_impersonation;
|
||||
oai_settings.human_sysprompt_message = settings.human_sysprompt_message ?? default_settings.human_sysprompt_message;
|
||||
oai_settings.image_inlining = settings.image_inlining ?? default_settings.image_inlining;
|
||||
oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality;
|
||||
oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check;
|
||||
@ -3045,7 +3065,6 @@ function loadOpenAISettings(data, settings) {
|
||||
$('#openai_proxy_password').val(oai_settings.proxy_password);
|
||||
$('#claude_assistant_prefill').val(oai_settings.assistant_prefill);
|
||||
$('#claude_assistant_impersonation').val(oai_settings.assistant_impersonation);
|
||||
$('#claude_human_sysprompt_textarea').val(oai_settings.human_sysprompt_message);
|
||||
$('#openai_image_inlining').prop('checked', oai_settings.image_inlining);
|
||||
$('#openai_bypass_status_check').prop('checked', oai_settings.bypass_status_check);
|
||||
|
||||
@ -3375,7 +3394,6 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
|
||||
show_external_models: settings.show_external_models,
|
||||
assistant_prefill: settings.assistant_prefill,
|
||||
assistant_impersonation: settings.assistant_impersonation,
|
||||
human_sysprompt_message: settings.human_sysprompt_message,
|
||||
claude_use_sysprompt: settings.claude_use_sysprompt,
|
||||
use_makersuite_sysprompt: settings.use_makersuite_sysprompt,
|
||||
use_alt_scale: settings.use_alt_scale,
|
||||
@ -3800,7 +3818,6 @@ function onSettingsPresetChange() {
|
||||
proxy_password: ['#openai_proxy_password', 'proxy_password', false],
|
||||
assistant_prefill: ['#claude_assistant_prefill', 'assistant_prefill', false],
|
||||
assistant_impersonation: ['#claude_assistant_impersonation', 'assistant_impersonation', false],
|
||||
human_sysprompt_message: ['#claude_human_sysprompt_textarea', 'human_sysprompt_message', false],
|
||||
claude_use_sysprompt: ['#claude_use_sysprompt', 'claude_use_sysprompt', true],
|
||||
use_makersuite_sysprompt: ['#use_makersuite_sysprompt', 'use_makersuite_sysprompt', true],
|
||||
use_alt_scale: ['#use_alt_scale', 'use_alt_scale', true],
|
||||
@ -4652,10 +4669,6 @@ function toggleChatCompletionForms() {
|
||||
const validSources = $(this).data('source').split(',');
|
||||
$(this).toggle(validSources.includes(oai_settings.chat_completion_source));
|
||||
});
|
||||
|
||||
if (chat_completion_sources.CLAUDE == oai_settings.chat_completion_source) {
|
||||
$('#claude_human_sysprompt_message_block').toggle(oai_settings.claude_use_sysprompt);
|
||||
}
|
||||
}
|
||||
|
||||
async function testApiConnection() {
|
||||
@ -5011,7 +5024,6 @@ export function initOpenAI() {
|
||||
|
||||
$('#claude_use_sysprompt').on('change', function () {
|
||||
oai_settings.claude_use_sysprompt = !!$('#claude_use_sysprompt').prop('checked');
|
||||
$('#claude_human_sysprompt_message_block').toggle(oai_settings.claude_use_sysprompt);
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
@ -5088,12 +5100,6 @@ export function initOpenAI() {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#claude_human_sysprompt_message_restore').on('click', function () {
|
||||
oai_settings.human_sysprompt_message = default_claude_human_sysprompt_message;
|
||||
$('#claude_human_sysprompt_textarea').val(oai_settings.human_sysprompt_message);
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#newgroupchat_prompt_restore').on('click', function () {
|
||||
oai_settings.new_group_chat_prompt = default_new_group_chat_prompt;
|
||||
$('#newgroupchat_prompt_textarea').val(oai_settings.new_group_chat_prompt);
|
||||
@ -5185,11 +5191,6 @@ export function initOpenAI() {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#claude_human_sysprompt_textarea').on('input', function () {
|
||||
oai_settings.human_sysprompt_message = String($('#claude_human_sysprompt_textarea').val());
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#openrouter_use_fallback').on('input', function () {
|
||||
oai_settings.openrouter_use_fallback = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
|
@ -658,6 +658,10 @@ async function CreateZenSliders(elmnt) {
|
||||
numSteps = 50;
|
||||
decimals = 1;
|
||||
}
|
||||
if (sliderID == 'nsigma') {
|
||||
numSteps = 50;
|
||||
decimals = 1;
|
||||
}
|
||||
//customize steps
|
||||
if (sliderID == 'mirostat_mode_textgenerationwebui' ||
|
||||
sliderID == 'mirostat_mode_kobold') {
|
||||
@ -702,6 +706,7 @@ async function CreateZenSliders(elmnt) {
|
||||
sliderID == 'penalty_alpha_textgenerationwebui' ||
|
||||
sliderID == 'length_penalty_textgenerationwebui' ||
|
||||
sliderID == 'epsilon_cutoff_textgenerationwebui' ||
|
||||
sliderID == 'nsigma' ||
|
||||
sliderID == 'rep_pen_range' ||
|
||||
sliderID == 'eta_cutoff_textgenerationwebui' ||
|
||||
sliderID == 'top_a_textgenerationwebui' ||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { escapeRegex } from '../utils.js';
|
||||
import { SlashCommand } from './SlashCommand.js';
|
||||
import { SlashCommandParser } from './SlashCommandParser.js';
|
||||
|
||||
export class SlashCommandBrowser {
|
||||
@ -30,7 +29,7 @@ export class SlashCommandBrowser {
|
||||
this.details?.remove();
|
||||
this.details = null;
|
||||
let query = inp.value.trim();
|
||||
if (query.slice(-1) == '"' && !/(?:^|\s+)"/.test(query)) {
|
||||
if (query.slice(-1) === '"' && !/(?:^|\s+)"/.test(query)) {
|
||||
query = `"${query}`;
|
||||
}
|
||||
let fuzzyList = [];
|
||||
@ -59,7 +58,7 @@ export class SlashCommandBrowser {
|
||||
cmd.helpString,
|
||||
];
|
||||
const find = ()=>targets.find(t=>(fuzzyList.find(f=>f.test(t)) ?? quotedList.find(q=>t.includes(q))) !== undefined) !== undefined;
|
||||
if (fuzzyList.length + quotedList.length == 0 || find()) {
|
||||
if (fuzzyList.length + quotedList.length === 0 || find()) {
|
||||
this.itemMap[cmd.name].classList.remove('isFiltered');
|
||||
} else {
|
||||
this.itemMap[cmd.name].classList.add('isFiltered');
|
||||
@ -78,7 +77,7 @@ export class SlashCommandBrowser {
|
||||
list.classList.add('autoComplete');
|
||||
this.cmdList = Object
|
||||
.keys(SlashCommandParser.commands)
|
||||
.filter(key => SlashCommandParser.commands[key].name == key) // exclude aliases
|
||||
.filter(key => SlashCommandParser.commands[key].name === key) // exclude aliases
|
||||
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
|
||||
.map(key => SlashCommandParser.commands[key])
|
||||
;
|
||||
@ -97,7 +96,7 @@ export class SlashCommandBrowser {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.details != details) {
|
||||
if (this.details !== details) {
|
||||
Array.from(list.querySelectorAll('.selected')).forEach(it=>it.classList.remove('selected'));
|
||||
item.classList.add('selected');
|
||||
this.details?.remove();
|
||||
@ -124,7 +123,7 @@ export class SlashCommandBrowser {
|
||||
parent.append(this.dom);
|
||||
|
||||
this.mo = new MutationObserver(muts=>{
|
||||
if (muts.find(mut=>Array.from(mut.removedNodes).find(it=>it == this.dom || it.contains(this.dom)))) {
|
||||
if (muts.find(mut=>Array.from(mut.removedNodes).find(it=>it === this.dom || it.contains(this.dom)))) {
|
||||
this.mo.disconnect();
|
||||
window.removeEventListener('keydown', boundHandler);
|
||||
}
|
||||
@ -136,7 +135,7 @@ export class SlashCommandBrowser {
|
||||
}
|
||||
|
||||
handleKeyDown(evt) {
|
||||
if (!evt.shiftKey && !evt.altKey && evt.ctrlKey && evt.key.toLowerCase() == 'f') {
|
||||
if (!evt.shiftKey && !evt.altKey && evt.ctrlKey && evt.key.toLowerCase() === 'f') {
|
||||
if (!this.dom.closest('body')) return;
|
||||
if (this.dom.closest('.mes') && !this.dom.closest('.last_mes')) return;
|
||||
evt.preventDefault();
|
||||
|
@ -193,6 +193,7 @@ const settings = {
|
||||
openrouter_allow_fallbacks: true,
|
||||
xtc_threshold: 0.1,
|
||||
xtc_probability: 0,
|
||||
nsigma: 0.0,
|
||||
featherless_model: '',
|
||||
};
|
||||
|
||||
@ -265,6 +266,7 @@ export const setting_names = [
|
||||
'openrouter_allow_fallbacks',
|
||||
'xtc_threshold',
|
||||
'xtc_probability',
|
||||
'nsigma',
|
||||
];
|
||||
|
||||
const DYNATEMP_BLOCK = document.getElementById('dynatemp_block_ooba');
|
||||
@ -880,6 +882,13 @@ function setSettingByName(setting, value, trigger) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a streaming request for textgenerationwebui.
|
||||
* @param generate_data
|
||||
* @param signal
|
||||
* @returns {Promise<(function(): AsyncGenerator<{swipes: [], text: string, toolCalls: [], logprobs: {token: string, topLogprobs: Candidate[]}|null}, void, *>)|*>}
|
||||
* @throws {Error} - If the response status is not OK, or from within the generator
|
||||
*/
|
||||
async function generateTextGenWithStreaming(generate_data, signal) {
|
||||
generate_data.stream = true;
|
||||
|
||||
@ -995,6 +1004,7 @@ export function parseTabbyLogprobs(data) {
|
||||
* @param {Response} response - Response from the server.
|
||||
* @param {string} decoded - Decoded response body.
|
||||
* @returns {void} Nothing.
|
||||
* @throws {Error} If the response contains an error message, throws Error with the message.
|
||||
*/
|
||||
function tryParseStreamingError(response, decoded) {
|
||||
let data = {};
|
||||
@ -1178,6 +1188,7 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate,
|
||||
'sampler_order': settings.type === textgen_types.KOBOLDCPP ? settings.sampler_order : undefined,
|
||||
'xtc_threshold': settings.xtc_threshold,
|
||||
'xtc_probability': settings.xtc_probability,
|
||||
'nsigma': settings.nsigma,
|
||||
};
|
||||
const nonAphroditeParams = {
|
||||
'rep_pen': settings.rep_pen,
|
||||
@ -1245,7 +1256,9 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate,
|
||||
'dynatemp_exponent': dynatemp ? settings.dynatemp_exponent : undefined,
|
||||
'xtc_threshold': settings.xtc_threshold,
|
||||
'xtc_probability': settings.xtc_probability,
|
||||
'nsigma': settings.nsigma,
|
||||
'custom_token_bans': toIntArray(banned_tokens),
|
||||
'no_repeat_ngram_size': settings.no_repeat_ngram_size,
|
||||
};
|
||||
|
||||
if (settings.type === OPENROUTER) {
|
||||
|
@ -102,7 +102,7 @@ async function sendClaudeRequest(request, response) {
|
||||
const additionalHeaders = {};
|
||||
const useTools = request.body.model.startsWith('claude-3') && Array.isArray(request.body.tools) && request.body.tools.length > 0;
|
||||
const useSystemPrompt = (request.body.model.startsWith('claude-2') || request.body.model.startsWith('claude-3')) && request.body.claude_use_sysprompt;
|
||||
const convertedPrompt = convertClaudeMessages(request.body.messages, request.body.assistant_prefill, useSystemPrompt, useTools, request.body.human_sysprompt_message, request.body.char_name, request.body.user_name);
|
||||
const convertedPrompt = convertClaudeMessages(request.body.messages, request.body.assistant_prefill, useSystemPrompt, useTools, request.body.char_name, request.body.user_name);
|
||||
// Add custom stop sequences
|
||||
const stopSequences = [];
|
||||
if (Array.isArray(request.body.stop)) {
|
||||
@ -1051,8 +1051,12 @@ router.post('/generate', jsonParser, function (request, response) {
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Generation failed', error);
|
||||
const message = error.code === 'ECONNREFUSED'
|
||||
? `Connection refused: ${error.message}`
|
||||
: error.message || 'Unknown error occurred';
|
||||
|
||||
if (!response.headersSent) {
|
||||
response.send({ error: true });
|
||||
response.status(502).send({ error: { message, ...error } });
|
||||
} else {
|
||||
response.end();
|
||||
}
|
||||
@ -1068,7 +1072,7 @@ router.post('/generate', jsonParser, function (request, response) {
|
||||
|
||||
const message = errorResponse.statusText || 'Unknown error occurred';
|
||||
const quota_error = errorResponse.status === 429 && errorData?.error?.type === 'insufficient_quota';
|
||||
console.log(message, responseText);
|
||||
console.log('Chat completion request error: ', message, responseText);
|
||||
|
||||
if (!response.headersSent) {
|
||||
response.send({ error: { message }, quota_error: quota_error });
|
||||
|
@ -24,6 +24,8 @@ const defaultAvatarPath = './public/img/ai4.png';
|
||||
|
||||
// KV-store for parsed character data
|
||||
const characterDataCache = new Map();
|
||||
// Some Android devices require tighter memory management
|
||||
const isAndroid = process.platform === 'android';
|
||||
|
||||
/**
|
||||
* Reads the character card from the specified image file.
|
||||
@ -39,7 +41,7 @@ async function readCharacterData(inputFile, inputFormat = 'png') {
|
||||
}
|
||||
|
||||
const result = parse(inputFile, inputFormat);
|
||||
characterDataCache.set(cacheKey, result);
|
||||
!isAndroid && characterDataCache.set(cacheKey, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import { publicLibConfig } from '../../webpack.config.js';
|
||||
export default function getWebpackServeMiddleware() {
|
||||
const compiler = webpack(publicLibConfig);
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
if (process.env.NODE_ENV === 'production' || process.platform === 'android') {
|
||||
compiler.hooks.done.tap('serve', () => {
|
||||
if (compiler.watching) {
|
||||
compiler.watching.close(() => { });
|
||||
|
@ -91,11 +91,10 @@ export function convertClaudePrompt(messages, addAssistantPostfix, addAssistantP
|
||||
* @param {string} prefillString User determined prefill string
|
||||
* @param {boolean} useSysPrompt See if we want to use a system prompt
|
||||
* @param {boolean} useTools See if we want to use tools
|
||||
* @param {string} humanMsgFix Add Human message between system prompt and assistant.
|
||||
* @param {string} charName Character name
|
||||
* @param {string} userName User name
|
||||
*/
|
||||
export function convertClaudeMessages(messages, prefillString, useSysPrompt, useTools, humanMsgFix, charName = '', userName = '') {
|
||||
export function convertClaudeMessages(messages, prefillString, useSysPrompt, useTools, charName, userName) {
|
||||
let systemPrompt = [];
|
||||
if (useSysPrompt) {
|
||||
// Collect all the system messages up until the first instance of a non-system message, and then remove them from the messages array.
|
||||
@ -122,10 +121,10 @@ export function convertClaudeMessages(messages, prefillString, useSysPrompt, use
|
||||
|
||||
// Check if the first message in the array is of type user, if not, interject with humanMsgFix or a blank message.
|
||||
// Also prevents erroring out if the messages array is empty.
|
||||
if (messages.length === 0 || (messages.length > 0 && messages[0].role !== 'user')) {
|
||||
if (messages.length === 0) {
|
||||
messages.unshift({
|
||||
role: 'user',
|
||||
content: humanMsgFix || PROMPT_PLACEHOLDER,
|
||||
content: PROMPT_PLACEHOLDER,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user