diff --git a/default/settings.json b/default/settings.json
index 6a181a1449..e81817719e 100644
--- a/default/settings.json
+++ b/default/settings.json
@@ -405,7 +405,6 @@
"typical": 1,
"tfs": 1,
"rep_pen_slope": 0,
- "single_line": false,
"streaming_kobold": false,
"sampler_order": [
6,
diff --git a/package-lock.json b/package-lock.json
index 19eb2d6fad..5431117768 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "sillytavern",
- "version": "1.10.6",
+ "version": "1.10.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sillytavern",
- "version": "1.10.6",
+ "version": "1.10.7",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
diff --git a/package.json b/package.json
index 185af0b1d2..a55a0f45f5 100644
--- a/package.json
+++ b/package.json
@@ -47,7 +47,7 @@
"type": "git",
"url": "https://github.com/SillyTavern/SillyTavern.git"
},
- "version": "1.10.6",
+ "version": "1.10.7",
"scripts": {
"start": "node server.js",
"start-multi": "node server.js --disableCsrf",
diff --git a/public/context/Adventure.json b/public/context/Adventure.json
index 9b90cba544..44ae59cc1a 100644
--- a/public/context/Adventure.json
+++ b/public/context/Adventure.json
@@ -5,7 +5,6 @@
"always_force_name2": false,
"trim_sentences": false,
"include_newline": false,
- "custom_stopping_strings": "[\"\\n\"]",
- "custom_stopping_strings_macro": true,
+ "single_line": true,
"name": "Adventure"
}
\ No newline at end of file
diff --git a/public/css/st-tailwind.css b/public/css/st-tailwind.css
index dca40662a4..fb8a537e5f 100644
--- a/public/css/st-tailwind.css
+++ b/public/css/st-tailwind.css
@@ -105,6 +105,10 @@
align-items: flex-end !important;
}
+.alignItemsBaseline {
+ align-items: baseline !important;
+}
+
.alignSelfStart {
align-self: start;
}
diff --git a/public/index.html b/public/index.html
index e5f1b3c18a..6b8b5ee4c2 100644
--- a/public/index.html
+++ b/public/index.html
@@ -234,11 +234,10 @@
Text
@@ -998,17 +997,6 @@ Text
-
-
-
-
- Generate only one line per request (KoboldAI only, ignored by KoboldCpp).
-
-
-
+
+
Samplers Order
@@ -2233,7 +2229,8 @@
PaLM API Key
-
Advanced Formatting
+
+ Advanced Formatting
?
@@ -2463,6 +2460,52 @@ Instruct Mode
-
-
-
-
-
-
-
-
-
- Start Reply With
-
-
+
-
+
+
+ Start Reply With
+
+
+
+
+
+
-
-
-
+
+
Custom Stopping Strings
?
-
+
- JSON serialized array of strings, for example:
- ["\n", "\nUser:", "\nChar:"]
+ JSON serialized array of strings
-
-
-
+
+
+
+
-
diff --git a/public/script.js b/public/script.js
index edb74c1cea..659b4a2537 100644
--- a/public/script.js
+++ b/public/script.js
@@ -144,7 +144,7 @@ import {
onlyUnique,
} from "./scripts/utils.js";
-import { ModuleWorkerWrapper, extension_settings, getContext, loadExtensionSettings, processExtensionHelpers, registerExtensionHelper, renderExtensionTemplate, runGenerationInterceptors, saveMetadataDebounced } from "./scripts/extensions.js";
+import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, loadExtensionSettings, processExtensionHelpers, registerExtensionHelper, renderExtensionTemplate, runGenerationInterceptors, saveMetadataDebounced } from "./scripts/extensions.js";
import { COMMENT_NAME_DEFAULT, executeSlashCommands, getSlashCommandsHelp, registerSlashCommand } from "./scripts/slash-commands.js";
import {
tag_map,
@@ -728,6 +728,7 @@ async function firstLoadInit() {
initRossMods();
initStats();
initCfg();
+ doDailyExtensionUpdatesCheck();
}
function checkOnlineStatus() {
@@ -1840,6 +1841,10 @@ function getStoppingStrings(isImpersonate) {
result.push(...customStoppingStrings);
}
+ if (power_user.single_line) {
+ result.unshift('\n');
+ }
+
return result.filter(onlyUnique);
}
@@ -8815,7 +8820,7 @@ jQuery(async function () {
}
restoreCaretPosition($(this).get(0), caretPosition);
- }, 500);
+ }, 2000);
})
$(".user_stats_button").on('click', function () {
diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js
index 0e519c125a..7942fdda4d 100644
--- a/public/scripts/extensions.js
+++ b/public/scripts/extensions.js
@@ -733,8 +733,9 @@ export async function installExtension(url) {
});
if (!request.ok) {
- toastr.info(request.statusText, 'Extension installation failed');
- console.error('Extension installation failed', request.status, request.statusText);
+ const text = await request.text();
+ toastr.warning(text || request.statusText, 'Extension installation failed', { timeOut: 5000 });
+ console.error('Extension installation failed', request.status, request.statusText, text);
return;
}
@@ -773,10 +774,14 @@ async function loadExtensionSettings(settings, versionChanged) {
if (extension_settings.autoConnect && extension_settings.apiUrl) {
connectToApi(extension_settings.apiUrl);
}
+}
- if (extension_settings.notifyUpdates) {
- checkForExtensionUpdates(false);
- }
+export function doDailyExtensionUpdatesCheck() {
+ setTimeout(() => {
+ if (extension_settings.notifyUpdates) {
+ checkForExtensionUpdates(false);
+ }
+ }, 1);
}
/**
diff --git a/public/scripts/extensions/assets/index.js b/public/scripts/extensions/assets/index.js
index 78ea750610..fe6cd12efa 100644
--- a/public/scripts/extensions/assets/index.js
+++ b/public/scripts/extensions/assets/index.js
@@ -55,6 +55,14 @@ function downloadAssetsList(url) {
for (const assetType of assetTypes) {
let assetTypeMenu = $('
', { id: "assets_audio_ambient_div", class: "assets-list-div" });
assetTypeMenu.append(`${assetType}
`)
+
+ if (assetType == 'extension') {
+ assetTypeMenu.append(`
+
+ To download extensions from this page, you need to have
Git installed.
+
`);
+ }
+
for (const i in availableAssets[assetType]) {
const asset = availableAssets[assetType][i];
const elemId = `assets_install_${assetType}_${i}`;
diff --git a/public/scripts/extensions/assets/style.css b/public/scripts/extensions/assets/style.css
index 5bd10be567..15c84d7238 100644
--- a/public/scripts/extensions/assets/style.css
+++ b/public/scripts/extensions/assets/style.css
@@ -13,11 +13,17 @@
padding: 5px;
}
+.assets-list-git {
+ font-size: calc(var(--mainFontSize) * 0.8);
+ opacity: 0.8;
+ margin-bottom: 1em;
+}
+
.assets-list-div h3 {
text-transform: capitalize;
}
-.assets-list-div a {
+.assets-list-div i a {
color: inherit;
}
diff --git a/public/scripts/kai-settings.js b/public/scripts/kai-settings.js
index 517e32b2f7..f7c8083086 100644
--- a/public/scripts/kai-settings.js
+++ b/public/scripts/kai-settings.js
@@ -20,7 +20,6 @@ export const kai_settings = {
typical: 1,
tfs: 1,
rep_pen_slope: 0.9,
- single_line: false,
streaming_kobold: false,
sampler_order: [0, 1, 2, 3, 4, 5, 6],
mirostat: 0,
@@ -28,6 +27,7 @@ export const kai_settings = {
mirostat_eta: 0.1,
use_default_badwordsids: false,
grammar: "",
+ seed: -1,
};
export const kai_flags = {
@@ -75,11 +75,6 @@ export function loadKoboldSettings(preset) {
$(slider.counterId).val(formattedValue);
}
- // TODO: refactor checkboxes (if adding any more)
- if (preset.hasOwnProperty('single_line')) {
- kai_settings.single_line = preset.single_line;
- $('#single_line').prop('checked', kai_settings.single_line);
- }
if (preset.hasOwnProperty('streaming_kobold')) {
kai_settings.streaming_kobold = preset.streaming_kobold;
$('#streaming_kobold').prop('checked', kai_settings.streaming_kobold);
@@ -127,7 +122,7 @@ export function getKoboldGenerationData(finalPrompt, settings, maxLength, maxCon
s6: sampler_order[5],
s7: sampler_order[6],
use_world_info: false,
- singleline: kai_settings.single_line,
+ singleline: false,
stop_sequence: (kai_flags.can_use_stop_sequence || isHorde) ? getStoppingStrings(isImpersonate) : undefined,
streaming: kai_settings.streaming_kobold && kai_flags.can_use_streaming && type !== 'quiet',
can_abort: kai_flags.can_use_streaming,
@@ -136,6 +131,7 @@ export function getKoboldGenerationData(finalPrompt, settings, maxLength, maxCon
mirostat_eta: kai_flags.can_use_mirostat ? kai_settings.mirostat_eta : undefined,
use_default_badwordsids: kai_flags.can_use_default_badwordsids ? kai_settings.use_default_badwordsids : undefined,
grammar: kai_flags.can_use_grammar ? substituteParams(kai_settings.grammar) : undefined,
+ sampler_seed: kai_settings.seed >= 0 ? kai_settings.seed : undefined,
};
return generate_data;
}
@@ -281,6 +277,13 @@ const sliders = [
format: (val) => val,
setValue: (val) => { kai_settings.grammar = val; },
},
+ {
+ name: "seed",
+ sliderId: "#seed_kobold",
+ counterId: "#seed_counter_kobold",
+ format: (val) => val,
+ setValue: (val) => { kai_settings.seed = Number(val); },
+ },
];
export function setKoboldFlags(version, koboldVersion) {
@@ -380,12 +383,6 @@ jQuery(function () {
});
});
- $('#single_line').on("input", function () {
- const value = !!$(this).prop('checked');
- kai_settings.single_line = value;
- saveSettingsDebounced();
- });
-
$('#streaming_kobold').on("input", function () {
const value = !!$(this).prop('checked');
kai_settings.streaming_kobold = value;
diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js
index ce689e41aa..5f5cc761e1 100644
--- a/public/scripts/power-user.js
+++ b/public/scripts/power-user.js
@@ -46,8 +46,9 @@ export {
export const MAX_CONTEXT_DEFAULT = 8192;
const MAX_CONTEXT_UNLOCKED = 65536;
-const unlockedMaxContextStep = 4096
-const unlockedMaxContestMin = 8192
+const unlockedMaxContextStep = 256;
+const maxContextMin = 512;
+const maxContextStep = 64;
const defaultStoryString = "{{#if system}}{{system}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}";
const defaultExampleSeparator = '***';
@@ -169,6 +170,7 @@ let power_user = {
relaxed_api_urls: false,
world_import_dialog: true,
disable_group_trimming: false,
+ single_line: false,
default_instruct: '',
instruct: {
@@ -258,11 +260,10 @@ const contextControls = [
{ id: "context_chat_start", property: "chat_start", isCheckbox: false, isGlobalSetting: false },
// Existing power user settings
- { id: "always-force-name2-checkbox", property: "always_force_name2", isCheckbox: true, isGlobalSetting: true },
- { id: "trim_sentences_checkbox", property: "trim_sentences", isCheckbox: true, isGlobalSetting: true },
- { id: "include_newline_checkbox", property: "include_newline", isCheckbox: true, isGlobalSetting: true },
- { id: "custom_stopping_strings", property: "custom_stopping_strings", isCheckbox: false, isGlobalSetting: true },
- { id: "custom_stopping_strings_macro", property: "custom_stopping_strings_macro", isCheckbox: true, isGlobalSetting: true }
+ { id: "always-force-name2-checkbox", property: "always_force_name2", isCheckbox: true, isGlobalSetting: true, defaultValue: true },
+ { id: "trim_sentences_checkbox", property: "trim_sentences", isCheckbox: true, isGlobalSetting: true, defaultValue: false },
+ { id: "include_newline_checkbox", property: "include_newline", isCheckbox: true, isGlobalSetting: true, defaultValue: false },
+ { id: "single_line", property: "single_line", isCheckbox: true, isGlobalSetting: true, defaultValue: false },
];
let browser_has_focus = true;
@@ -923,6 +924,7 @@ function loadPowerUserSettings(settings, data) {
power_user.tokenizer = tokenizers.GPT2;
}
+ $('#single_line').prop("checked", power_user.single_line);
$('#relaxed_api_urls').prop("checked", power_user.relaxed_api_urls);
$('#world_import_dialog').prop("checked", power_user.world_import_dialog);
$('#trim_spaces').prop("checked", power_user.trim_spaces);
@@ -1087,13 +1089,16 @@ function loadMaxContextUnlocked() {
function switchMaxContextSize() {
const elements = [$('#max_context'), $('#rep_pen_range'), $('#rep_pen_range_textgenerationwebui')];
const maxValue = power_user.max_context_unlocked ? MAX_CONTEXT_UNLOCKED : MAX_CONTEXT_DEFAULT;
- const minValue = power_user.max_context_unlocked ? unlockedMaxContestMin : 0;
- const steps = power_user.max_context_unlocked ? unlockedMaxContextStep : 256;
+ const minValue = power_user.max_context_unlocked ? maxContextMin : maxContextMin;
+ const steps = power_user.max_context_unlocked ? unlockedMaxContextStep : maxContextStep;
for (const element of elements) {
element.attr('max', maxValue);
element.attr('step', steps);
- element.attr('min', minValue);
+
+ if (element.attr('id') == 'max_context') {
+ element.attr('min', minValue);
+ }
const value = Number(element.val());
if (value >= maxValue) {
@@ -1172,11 +1177,13 @@ function loadContextSettings() {
power_user.context.preset = name;
contextControls.forEach(control => {
- if (preset[control.property] !== undefined) {
+ const presetValue = preset[control.property] ?? control.defaultValue;
+
+ if (presetValue !== undefined) {
if (control.isGlobalSetting) {
- power_user[control.property] = preset[control.property];
+ power_user[control.property] = presetValue;
} else {
- power_user.context[control.property] = preset[control.property];
+ power_user.context[control.property] = presetValue;
}
const $element = $(`#${control.id}`);
@@ -1937,6 +1944,12 @@ $(document).ready(() => {
saveSettingsDebounced();
});
+ $('#single_line').on("input", function () {
+ const value = !!$(this).prop('checked');
+ power_user.single_line = value;
+ saveSettingsDebounced();
+ });
+
$("#always-force-name2-checkbox").change(function () {
power_user.always_force_name2 = !!$(this).prop("checked");
saveSettingsDebounced();
@@ -2114,7 +2127,6 @@ $(document).ready(() => {
saveSettingsDebounced();
});
-
$("#user-mes-blur-tint-color-picker").on('change', (evt) => {
power_user.user_mes_blur_tint_color = evt.detail.rgba;
applyThemeColor('userMesBlurTint');
@@ -2152,7 +2164,6 @@ $(document).ready(() => {
power_user.movingUIPreset = movingUIPresetSelected;
applyMovingUIPreset(movingUIPresetSelected);
saveSettingsDebounced();
-
});
$("#ui-preset-save-button").on('click', saveTheme);
diff --git a/public/scripts/preset-manager.js b/public/scripts/preset-manager.js
index e8a012babe..0d75f40b27 100644
--- a/public/scripts/preset-manager.js
+++ b/public/scripts/preset-manager.js
@@ -262,6 +262,7 @@ class PresetManager {
'model_novel',
'streaming_kobold',
"enabled",
+ 'seed',
];
const settings = Object.assign({}, getSettingsByApiId(this.apiId));
diff --git a/server.js b/server.js
index fbcb4eddf4..b3b449ffd2 100644
--- a/server.js
+++ b/server.js
@@ -401,6 +401,7 @@ app.post("/generate", jsonParser, async function (request, response_generate) {
mirostat_eta: request.body.mirostat_eta,
mirostat_tau: request.body.mirostat_tau,
grammar: request.body.grammar,
+ sampler_seed: request.body.sampler_seed,
};
if (!!request.body.stop_sequence) {
this_settings['stop_sequence'] = request.body.stop_sequence;
diff --git a/src/extensions.js b/src/extensions.js
index 21d2a924ab..fec2142442 100644
--- a/src/extensions.js
+++ b/src/extensions.js
@@ -2,6 +2,7 @@ const path = require('path');
const fs = require('fs');
const { default: simpleGit } = require('simple-git');
const sanitize = require('sanitize-filename');
+const commandExistsSync = require('command-exists').sync;
const { DIRECTORIES } = require('./constants');
/**
@@ -61,12 +62,19 @@ function registerEndpoints(app, jsonParser) {
* @returns {void}
*/
app.post('/api/extensions/install', jsonParser, async (request, response) => {
- const git = simpleGit();
+ const gitExists = commandExistsSync('git');
+
+ if (!gitExists) {
+ return response.status(400).send('Server Error: git is not installed on the system.');
+ }
+
if (!request.body.url) {
return response.status(400).send('Bad Request: URL is required in the request body.');
}
try {
+ const git = simpleGit();
+
// make sure the third-party directory exists
if (!fs.existsSync(path.join(DIRECTORIES.extensions, 'third-party'))) {
fs.mkdirSync(path.join(DIRECTORIES.extensions, 'third-party'));
@@ -87,7 +95,6 @@ function registerEndpoints(app, jsonParser) {
return response.send({ version, author, display_name, extensionPath });
-
} catch (error) {
console.log('Importing custom content failed', error);
return response.status(500).send(`Server Error: ${error.message}`);
diff --git a/statsHelpers.js b/statsHelpers.js
index ee344d303e..c370fa5881 100644
--- a/statsHelpers.js
+++ b/statsHelpers.js
@@ -173,8 +173,12 @@ async function loadStatsFile(chatsPath, charactersPath, recreateStats = false) {
async function saveStatsToFile() {
if (charStats.timestamp > lastSaveTimestamp) {
//console.debug("Saving stats to file...");
- await writeFile(statsFilePath, JSON.stringify(charStats));
- lastSaveTimestamp = Date.now();
+ try {
+ await writeFile(statsFilePath, JSON.stringify(charStats));
+ lastSaveTimestamp = Date.now();
+ } catch (error) {
+ console.log("Failed to save stats to file.", error);
+ }
} else {
//console.debug('Stats have not changed since last save. Skipping file write.');
}
@@ -184,9 +188,9 @@ async function saveStatsToFile() {
* Attempts to save charStats to a file and then terminates the process.
* If an error occurs during the file write, it logs the error before exiting.
*/
-async function writeStatsToFileAndExit(charStats) {
+async function writeStatsToFileAndExit() {
try {
- await saveStatsToFile(charStats);
+ await saveStatsToFile();
} catch (err) {
console.error("Failed to write stats to file:", err);
} finally {