Merge branch 'staging' of http://github.com/cohee1207/SillyTavern into staging
This commit is contained in:
commit
e15c739e64
|
@ -1,9 +1,9 @@
|
|||
name: Build and Publish Release (Dev)
|
||||
name: Build and Publish Release (Release)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- release
|
||||
|
||||
jobs:
|
||||
build_and_publish:
|
||||
|
@ -30,8 +30,8 @@ jobs:
|
|||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: dist/*
|
||||
tag_name: ci-dev
|
||||
name: Continuous Release (Dev)
|
||||
tag_name: ci-release
|
||||
name: Continuous Release (Release)
|
||||
prerelease: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@ -1,9 +1,9 @@
|
|||
name: Build and Publish Release (Main)
|
||||
name: Build and Publish Release (Staging)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
|
||||
jobs:
|
||||
build_and_publish:
|
||||
|
@ -30,8 +30,8 @@ jobs:
|
|||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: dist/*
|
||||
tag_name: ci-main
|
||||
name: Continuous Release (Main)
|
||||
tag_name: ci-staging
|
||||
name: Continuous Release (Staging)
|
||||
prerelease: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@ -9,12 +9,14 @@ public/worlds/
|
|||
public/css/bg_load.css
|
||||
public/themes/
|
||||
public/OpenAI Settings/
|
||||
public/KoboldAI Settings/
|
||||
public/TextGen Settings/
|
||||
public/scripts/extensions/third-party/
|
||||
public/stats.json
|
||||
/uploads/
|
||||
*.jsonl
|
||||
/config.conf
|
||||
/docker/config.conf
|
||||
/docker/config
|
||||
.DS_Store
|
||||
public/settings.json
|
||||
/thumbnails
|
||||
|
|
|
@ -4,7 +4,7 @@ FROM node:19.1.0-alpine3.16
|
|||
ARG APP_HOME=/home/node/app
|
||||
|
||||
# Install system dependencies
|
||||
RUN apk add gcompat tini
|
||||
RUN apk add gcompat tini git
|
||||
|
||||
# Ensure proper handling of kernel signals
|
||||
ENTRYPOINT [ "tini", "--" ]
|
||||
|
@ -23,13 +23,17 @@ COPY . ./
|
|||
|
||||
# Copy default chats, characters and user avatars to <folder>.default folder
|
||||
RUN \
|
||||
IFS="," RESOURCES="characters,chats,groups,group chats,User Avatars,worlds,settings.json" && \
|
||||
IFS="," RESOURCES="characters,chats,groups,group chats,User Avatars,worlds" && \
|
||||
\
|
||||
echo "*** Store default $RESOURCES in <folder>.default ***" && \
|
||||
for R in $RESOURCES; do mv "public/$R" "public/$R.default"; done && \
|
||||
\
|
||||
echo "*** Create symbolic links to config directory ***" && \
|
||||
for R in $RESOURCES; do ln -s "../config/$R" "public/$R"; done && \
|
||||
# rm "config.conf" "public/settings.json" "public/css/bg_load.css" && \
|
||||
ln -s "./config/config.conf" "config.conf" && \
|
||||
ln -s "../config/settings.json" "public/settings.json" && \
|
||||
ln -s "../../config/bg_load.css" "public/css/bg_load.css" && \
|
||||
mkdir "config"
|
||||
|
||||
# Cleanup unnecessary files
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 338 KiB After Width: | Height: | Size: 338 KiB |
|
@ -9,5 +9,4 @@ services:
|
|||
- "8000:8000"
|
||||
volumes:
|
||||
- "./config:/home/node/app/config"
|
||||
- "./config.conf:/home/node/app/config.conf"
|
||||
restart: unless-stopped
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Initialize missing user files
|
||||
IFS="," RESOURCES="characters,groups,group chats,chats,User Avatars,worlds,settings.json"
|
||||
IFS="," RESOURCES="characters,groups,group chats,chats,User Avatars,worlds"
|
||||
for R in $RESOURCES; do
|
||||
if [ ! -e "config/$R" ]; then
|
||||
echo "Resource not found, copying from defaults: $R"
|
||||
|
@ -9,5 +9,20 @@ for R in $RESOURCES; do
|
|||
fi
|
||||
done
|
||||
|
||||
if [ ! -e "config/config.conf" ]; then
|
||||
echo "Resource not found, copying from defaults: config.conf"
|
||||
cp -r "default/config.conf" "config/config.conf"
|
||||
fi
|
||||
|
||||
if [ ! -e "config/settings.json" ]; then
|
||||
echo "Resource not found, copying from defaults: settings.json"
|
||||
cp -r "default/settings.json" "config/settings.json"
|
||||
fi
|
||||
|
||||
if [ ! -e "config/bg_load.css" ]; then
|
||||
echo "Resource not found, copying from defaults: bg_load.css"
|
||||
cp -r "default/bg_load.css" "config/bg_load.css"
|
||||
fi
|
||||
|
||||
# Start the server
|
||||
exec node server.js
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"max_length": 100,
|
||||
"genamt": 100,
|
||||
"max_length": 2048,
|
||||
"genamt": 200,
|
||||
"temp": 1,
|
||||
"top_k": 0,
|
||||
"top_p": 0.95,
|
||||
|
@ -19,4 +19,4 @@
|
|||
4,
|
||||
5
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,10 @@
|
|||
"repetition_penalty_range": 8192,
|
||||
"repetition_penalty_frequency": 0.03,
|
||||
"repetition_penalty_presence": 0.005,
|
||||
"repetition_penalty_slope": 0,
|
||||
"top_a": 0.075,
|
||||
"top_k": 79,
|
||||
"top_p": 0.95
|
||||
"top_p": 0.95,
|
||||
"typical_p": 1,
|
||||
"max_context": 8192
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
"min_length": 1,
|
||||
"top_k": 25,
|
||||
"top_p": 1,
|
||||
"top_a": 0,
|
||||
"typical_p": 1,
|
||||
"tail_free_sampling": 0.925,
|
||||
"repetition_penalty": 1.9,
|
||||
"repetition_penalty_range": 768,
|
||||
|
@ -15,4 +17,4 @@
|
|||
"return_full_text": false,
|
||||
"prefix": "vanilla",
|
||||
"max_context": 8192
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
"max_length": 40,
|
||||
"min_length": 1,
|
||||
"top_a": 0.022,
|
||||
"top_k": 0,
|
||||
"top_p": 1,
|
||||
"typical_p": 0.9,
|
||||
"tail_free_sampling": 0.956,
|
||||
"repetition_penalty": 1.25,
|
||||
|
@ -15,4 +17,4 @@
|
|||
"return_full_text": false,
|
||||
"prefix": "vanilla",
|
||||
"max_context": 8192
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"min_length": 1,
|
||||
"top_k": 25,
|
||||
"top_a": 0.3,
|
||||
"top_p": 1,
|
||||
"typical_p": 0.96,
|
||||
"tail_free_sampling": 0.895,
|
||||
"repetition_penalty": 1.0125,
|
||||
|
@ -16,4 +17,4 @@
|
|||
"return_full_text": false,
|
||||
"prefix": "vanilla",
|
||||
"max_context": 8192
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"top_k": 79,
|
||||
"top_p": 0.95,
|
||||
"top_a": 0.075,
|
||||
"typical_p": 1,
|
||||
"tail_free_sampling": 0.989,
|
||||
"repetition_penalty": 1.5,
|
||||
"repetition_penalty_range": 8192,
|
||||
|
@ -16,4 +17,4 @@
|
|||
"return_full_text": false,
|
||||
"prefix": "vanilla",
|
||||
"max_context": 8192
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"min_length": 1,
|
||||
"top_k": 0,
|
||||
"top_p": 0.912,
|
||||
"top_a": 1,
|
||||
"typical_p": 0.912,
|
||||
"tail_free_sampling": 0.921,
|
||||
"repetition_penalty": 1.21,
|
||||
|
@ -16,4 +17,4 @@
|
|||
"return_full_text": false,
|
||||
"prefix": "vanilla",
|
||||
"max_context": 8192
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@
|
|||
<script type="module" src="scripts/context-template.js"></script>
|
||||
<script type="module" src="scripts/extensions.js"></script>
|
||||
<script type="module" src="scripts/authors-note.js"></script>
|
||||
<script type="module" src="scripts/preset-manager.js"></script>
|
||||
<script type="text/javascript" src="scripts/toolcool-color-picker.js"></script>
|
||||
|
||||
<title>SillyTavern</title>
|
||||
|
@ -131,15 +132,24 @@
|
|||
<div class="scrollableInner">
|
||||
<div class="flex-container" id="ai_response_configuration">
|
||||
<div id="respective-presets-block" class="width100p">
|
||||
<input type="file" hidden data-preset-manager-file="" accept=".json, .settings">
|
||||
<div id="kobold_api-presets">
|
||||
<h3><span data-i18n="kobldpresets">Kobold Presets</span>
|
||||
<a href="https://docs.sillytavern.app/usage/api-connections/koboldai/" class="notes-link" target="_blank">
|
||||
<span class="note-link-span">?</span>
|
||||
</a>
|
||||
</h3>
|
||||
<select id="settings_perset">
|
||||
<option value="gui" data-i18n="guikoboldaisettings">GUI KoboldAI Settings</option>
|
||||
</select>
|
||||
|
||||
<div class="preset_buttons">
|
||||
<select id="settings_perset" data-preset-manager-for="kobold">
|
||||
<option value="gui" data-i18n="guikoboldaisettings">GUI KoboldAI Settings</option>
|
||||
</select>
|
||||
<i data-preset-manager-update="kobold" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i>
|
||||
<i data-preset-manager-new="kobold" class="menu_button fa-solid fa-plus" title="Create new preset" data-i18n="[title]Create new preset"></i>
|
||||
<i data-preset-manager-import="kobold" class="menu_button fa-solid fa-upload" title="Import preset" data-i18n="[title]Import preset"></i>
|
||||
<i data-preset-manager-export="kobold" class="menu_button fa-solid fa-download"title="Export preset" data-i18n="[title]Export preset"></i>
|
||||
<i data-preset-manager-delete="kobold" class="menu_button fa-solid fa-trash-can" title="Delete the preset" data-i18n="[title]Delete the preset"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="novel_api-presets">
|
||||
<h3>
|
||||
|
@ -148,7 +158,7 @@
|
|||
<span class="note-link-span">?</span>
|
||||
</a>
|
||||
</h3>
|
||||
<select id="settings_perset_novel">
|
||||
<select id="settings_perset_novel" data-preset-manager-for="novel">
|
||||
<option value="gui" data-i18n="default">Default</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -171,8 +181,15 @@
|
|||
<div id="textgenerationwebui_api-presets">
|
||||
<h3><span data-i18n="text gen webio(ooba)preset">Text Gen WebUI (ooba) presets</span>
|
||||
</h3>
|
||||
<select id="settings_preset_textgenerationwebui">
|
||||
</select>
|
||||
<div class="preset_buttons">
|
||||
<select id="settings_preset_textgenerationwebui" data-preset-manager-for="textgenerationwebui">
|
||||
</select>
|
||||
<i data-preset-manager-update="textgenerationwebui" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i>
|
||||
<i data-preset-manager-new="textgenerationwebui" class="menu_button fa-solid fa-plus" title="Create new preset" data-i18n="[title]Create new preset"></i>
|
||||
<i data-preset-manager-import="textgenerationwebui" class="menu_button fa-solid fa-upload" title="Import preset" data-i18n="[title]Import preset"></i>
|
||||
<i data-preset-manager-export="textgenerationwebui" class="menu_button fa-solid fa-download"title="Export preset" data-i18n="[title]Export preset"></i>
|
||||
<i data-preset-manager-delete="textgenerationwebui" class="menu_button fa-solid fa-trash-can" title="Delete the preset" data-i18n="[title]Delete the preset"></i>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
|
@ -777,6 +794,81 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="novel_api-settings">
|
||||
<div class="range-block">
|
||||
<div class="range-block-title" data-i18n="Top P">
|
||||
Top P
|
||||
</div>
|
||||
<div class="range-block-range-and-counter">
|
||||
<div class="range-block-range">
|
||||
<input type="range" id="top_p_novel" name="volume" min="0" max="1" step="0.01">
|
||||
</div>
|
||||
<div class="range-block-counter">
|
||||
<div contenteditable="true" data-for="top_p_novel" id="top_p_counter_novel">
|
||||
select
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block">
|
||||
<div class="range-block-title" data-i18n="Top A">
|
||||
Top A
|
||||
</div>
|
||||
<div class="range-block-range-and-counter">
|
||||
<div class="range-block-range">
|
||||
<input type="range" id="top_a_novel" name="volume" min="0" max="1" step="0.01">
|
||||
</div>
|
||||
<div class="range-block-counter">
|
||||
<div contenteditable="true" data-for="top_a_novel" id="top_a_counter_novel">
|
||||
select
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block">
|
||||
<div class="range-block-title" data-i18n="Top K">
|
||||
Top K
|
||||
</div>
|
||||
<div class="range-block-range-and-counter">
|
||||
<div class="range-block-range">
|
||||
<input type="range" id="top_k_novel" name="volume" min="0" max="300" step="1">
|
||||
</div>
|
||||
<div class="range-block-counter">
|
||||
<div contenteditable="true" data-for="top_k_novel" id="top_k_counter_novel">
|
||||
select
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block">
|
||||
<div class="range-block-title" data-i18n="Typical P">
|
||||
Typical P
|
||||
</div>
|
||||
<div class="range-block-range-and-counter">
|
||||
<div class="range-block-range">
|
||||
<input type="range" id="typical_p_novel" name="volume" min="0" max="1" step="0.01">
|
||||
</div>
|
||||
<div class="range-block-counter">
|
||||
<div contenteditable="true" data-for="typical_p_novel" id="typical_p_counter_novel">
|
||||
select
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block">
|
||||
<div class="range-block-title" data-i18n="Min Length">
|
||||
Min Length
|
||||
</div>
|
||||
<div class="range-block-range-and-counter">
|
||||
<div class="range-block-range">
|
||||
<input type="range" id="min_length_novel" name="volume" min="0" max="1024" step="1">
|
||||
</div>
|
||||
<div class="range-block-counter">
|
||||
<div contenteditable="true" data-for="min_length_novel" id="min_length_counter_novel">
|
||||
select
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="textgenerationwebui_api-settings">
|
||||
<div class="range-block">
|
||||
|
@ -2340,7 +2432,7 @@
|
|||
<span data-i18n="Confirm message deletion">Confirm message deletion</span>
|
||||
</label>
|
||||
<label for="spoiler_free_mode"><input id="spoiler_free_mode" type="checkbox" />
|
||||
<span data-i18n="Spoiler Free Mode">Spolier Free Mode</span>
|
||||
<span data-i18n="Spoiler Free Mode">Spoiler Free Mode</span>
|
||||
</label>
|
||||
|
||||
<div class="inline-drawer wide100p flexFlowColumn">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Llama 2",
|
||||
"system_prompt": "Write {{user}}'s next reply in this fictional roleplay with {{char}}.\n<</SYS>>\n",
|
||||
"system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.\n<</SYS>>\n",
|
||||
"system_sequence": "[INST] <<SYS>>\n",
|
||||
"stop_sequence": "",
|
||||
"input_sequence": "[INST]",
|
||||
|
|
201
public/script.js
201
public/script.js
|
@ -76,6 +76,7 @@ import {
|
|||
persona_description_positions,
|
||||
loadMovingUIState,
|
||||
getCustomStoppingStrings,
|
||||
MAX_CONTEXT_DEFAULT,
|
||||
} from "./scripts/power-user.js";
|
||||
|
||||
import {
|
||||
|
@ -701,11 +702,11 @@ var is_use_scroll_holder = false;
|
|||
|
||||
//settings
|
||||
var settings;
|
||||
var koboldai_settings;
|
||||
var koboldai_setting_names;
|
||||
export let koboldai_settings;
|
||||
export let koboldai_setting_names;
|
||||
var preset_settings = "gui";
|
||||
var user_avatar = "you.png";
|
||||
var amount_gen = 80; //default max length of AI generated responses
|
||||
export var amount_gen = 80; //default max length of AI generated responses
|
||||
var max_context = 2048;
|
||||
|
||||
var is_pygmalion = false;
|
||||
|
@ -719,8 +720,8 @@ let extension_prompts = {};
|
|||
var main_api;// = "kobold";
|
||||
//novel settings
|
||||
let novel_tier;
|
||||
let novelai_settings;
|
||||
let novelai_setting_names;
|
||||
export let novelai_settings;
|
||||
export let novelai_setting_names;
|
||||
let abortController;
|
||||
|
||||
//css
|
||||
|
@ -2110,7 +2111,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||
// OpenAI doesn't need instruct mode. Use OAI main prompt instead.
|
||||
const isInstruct = power_user.instruct.enabled && main_api !== 'openai';
|
||||
const isImpersonate = type == "impersonate";
|
||||
const isContinue = type == 'continue';
|
||||
|
||||
message_already_generated = isImpersonate ? `${name1}: ` : `${name2}: `;
|
||||
// Name for the multigen prefix
|
||||
|
@ -2199,6 +2199,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||
type = 'continue';
|
||||
}
|
||||
|
||||
const isContinue = type == 'continue';
|
||||
deactivateSendButtons();
|
||||
|
||||
let { messageBias, promptBias, isUserPromptBias } = getBiasStrings(textareaText, type);
|
||||
|
@ -3151,6 +3152,17 @@ async function DupeChar() {
|
|||
return;
|
||||
}
|
||||
|
||||
const confirm = await callPopup(`
|
||||
<h3>Are you sure you want to duplicate this character?</h3>
|
||||
<span>If you just want to start a new chat with the same character, use "Start new chat" option in the bottom-left options menu.</span><br><br>`,
|
||||
'confirm',
|
||||
);
|
||||
|
||||
if (!confirm) {
|
||||
console.log('User cancelled duplication');
|
||||
return;
|
||||
}
|
||||
|
||||
const body = { avatar_url: characters[this_chid].avatar };
|
||||
const response = await fetch('/dupecharacter', {
|
||||
method: 'POST',
|
||||
|
@ -4907,11 +4919,6 @@ async function getSettings(type) {
|
|||
novelai_setting_names = {};
|
||||
novelai_setting_names = arr_holder;
|
||||
|
||||
nai_settings.preset_settings_novel = settings.preset_settings_novel;
|
||||
$(
|
||||
`#settings_perset_novel option[value=${novelai_setting_names[nai_settings.preset_settings_novel]}]`
|
||||
).attr("selected", "true");
|
||||
|
||||
//Load AI model config settings
|
||||
|
||||
amount_gen = settings.amount_gen;
|
||||
|
@ -4924,10 +4931,11 @@ async function getSettings(type) {
|
|||
showSwipeButtons();
|
||||
|
||||
// Kobold
|
||||
loadKoboldSettings(settings);
|
||||
loadKoboldSettings(settings.kai_settings ?? settings);
|
||||
|
||||
// Novel
|
||||
loadNovelSettings(settings);
|
||||
loadNovelSettings(settings.nai_settings ?? settings);
|
||||
$(`#settings_perset_novel option[value=${novelai_setting_names[nai_settings.preset_settings_novel]}]`).attr("selected", "true");
|
||||
|
||||
// TextGen
|
||||
loadTextGenSettings(data, settings);
|
||||
|
@ -5047,8 +5055,8 @@ async function saveSettings(type) {
|
|||
context_settings: context_settings,
|
||||
tags: tags,
|
||||
tag_map: tag_map,
|
||||
...nai_settings,
|
||||
...kai_settings,
|
||||
nai_settings: nai_settings,
|
||||
kai_settings: kai_settings,
|
||||
...oai_settings,
|
||||
}, null, 4),
|
||||
beforeSend: function () {
|
||||
|
@ -5080,7 +5088,23 @@ async function saveSettings(type) {
|
|||
});
|
||||
}
|
||||
|
||||
export function setGenerationParamsFromPreset(preset) {
|
||||
if (preset.genamt !== undefined) {
|
||||
amount_gen = preset.genamt;
|
||||
$("#amount_gen").val(amount_gen);
|
||||
$("#amount_gen_counter").text(`${amount_gen}`);
|
||||
}
|
||||
|
||||
if (preset.max_length !== undefined) {
|
||||
max_context = preset.max_length;
|
||||
|
||||
const needsUnlock = max_context > MAX_CONTEXT_DEFAULT;
|
||||
$('#max_context_unlocked').prop('checked', needsUnlock).trigger('change');
|
||||
|
||||
$("#max_context").val(max_context);
|
||||
$("#max_context_counter").text(`${max_context}`);
|
||||
}
|
||||
}
|
||||
|
||||
function setCharacterBlockHeight() {
|
||||
const $children = $("#rm_print_characters_block").children();
|
||||
|
@ -5591,11 +5615,19 @@ function onScenarioOverrideRemoveClick() {
|
|||
$(this).closest('.scenario_override').find('.chat_scenario').val('').trigger('input');
|
||||
}
|
||||
|
||||
function callPopup(text, type, inputValue = '', { okButton, rows } = {}) {
|
||||
function callPopup(text, type, inputValue = '', { okButton, rows, wide, large } = {}) {
|
||||
if (type) {
|
||||
popup_type = type;
|
||||
}
|
||||
|
||||
if (wide) {
|
||||
$("#dialogue_popup").addClass("wide_dialogue_popup");
|
||||
}
|
||||
|
||||
if (large) {
|
||||
$("#dialogue_popup").addClass("large_dialogue_popup");
|
||||
}
|
||||
|
||||
$("#dialogue_popup_cancel").css("display", "inline-block");
|
||||
switch (popup_type) {
|
||||
case "avatarToCrop":
|
||||
|
@ -6840,6 +6872,73 @@ function doCharListDisplaySwitch() {
|
|||
updateVisibleDivs('#rm_print_characters_block', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to handle the deletion of a character, given a specific popup type and character ID.
|
||||
* If popup type equals "del_ch", it will proceed with deletion otherwise it will exit the function.
|
||||
* It fetches the delete character route, sending necessary parameters, and in case of success,
|
||||
* it proceeds to delete character from UI and saves settings.
|
||||
* In case of error during the fetch request, it logs the error details.
|
||||
*
|
||||
* @param {string} popup_type - The type of popup currently active.
|
||||
* @param {string} this_chid - The character ID to be deleted.
|
||||
*/
|
||||
export async function handleDeleteCharacter(popup_type, this_chid) {
|
||||
if (popup_type !== "del_ch") {
|
||||
return;
|
||||
}
|
||||
|
||||
const delete_chats = !!$("#del_char_checkbox").prop("checked");
|
||||
const avatar = characters[this_chid].avatar;
|
||||
const name = characters[this_chid].name;
|
||||
|
||||
const msg = { avatar_url: avatar, delete_chats: delete_chats };
|
||||
|
||||
const response = await fetch('/deletecharacter', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify(msg),
|
||||
cache: 'no-cache',
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
await deleteCharacter(name, avatar);
|
||||
} else {
|
||||
console.error('Failed to delete character: ', response.status, response.statusText);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to delete a character from UI after character deletion API success.
|
||||
* It manages necessary UI changes such as closing advanced editing popup, unsetting
|
||||
* character ID, resetting characters array and chat metadata, deselecting character's tab
|
||||
* panel, removing character name from navigation tabs, clearing chat, removing character's
|
||||
* avatar from tag_map, fetching updated list of characters and updating the 'deleted
|
||||
* character' message.
|
||||
* It also ensures to save the settings after all the operations.
|
||||
*
|
||||
* @param {string} name - The name of the character to be deleted.
|
||||
* @param {string} avatar - The avatar URL of the character to be deleted.
|
||||
*/
|
||||
export async function deleteCharacter(name, avatar) {
|
||||
$("#character_cross").click();
|
||||
this_chid = "invalid-safety-id";
|
||||
characters.length = 0;
|
||||
name2 = systemUserName;
|
||||
chat = [...safetychat];
|
||||
chat_metadata = {};
|
||||
setRightTabSelectedClass();
|
||||
$(document.getElementById("rm_button_selected_ch")).children("h2").text("");
|
||||
clearChat();
|
||||
this_chid = undefined;
|
||||
delete tag_map[avatar];
|
||||
await getCharacters();
|
||||
select_rm_info("char_delete", name);
|
||||
printMessages();
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
if (isMobile() === true) {
|
||||
|
@ -7211,55 +7310,7 @@ $(document).ready(function () {
|
|||
}, 200);
|
||||
}
|
||||
if (popup_type == "del_ch") {
|
||||
console.log(
|
||||
"Deleting character -- ChID: " +
|
||||
this_chid +
|
||||
" -- Name: " +
|
||||
characters[this_chid].name
|
||||
);
|
||||
const delete_chats = !!$("#del_char_checkbox").prop("checked");
|
||||
const avatar = characters[this_chid].avatar;
|
||||
const name = characters[this_chid].name;
|
||||
const msg = new FormData($("#form_create").get(0)); // ID form
|
||||
msg.append("delete_chats", delete_chats);
|
||||
jQuery.ajax({
|
||||
method: "POST",
|
||||
url: "/deletecharacter",
|
||||
beforeSend: function () {
|
||||
},
|
||||
data: msg,
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
success: async function (html) {
|
||||
//RossAscends: New handling of character deletion that avoids page refreshes and should have
|
||||
// fixed char corruption due to cache problems.
|
||||
//due to how it is handled with 'popup_type', i couldn't find a way to make my method completely
|
||||
// modular, so keeping it in TAI-main.js as a new default.
|
||||
//this allows for dynamic refresh of character list after deleting a character.
|
||||
// closes advanced editing popup
|
||||
$("#character_cross").click();
|
||||
// unsets expected chid before reloading (related to getCharacters/printCharacters from using old arrays)
|
||||
this_chid = "invalid-safety-id";
|
||||
// resets the characters array, forcing getcharacters to reset
|
||||
characters.length = 0;
|
||||
name2 = systemUserName; // replaces deleted charcter name with system user since she will be displayed next.
|
||||
chat = [...safetychat]; // sets up system user to tell user about having deleted a character
|
||||
chat_metadata = {}; // resets chat metadata
|
||||
setRightTabSelectedClass() // 'deselects' character's tab panel
|
||||
$(document.getElementById("rm_button_selected_ch"))
|
||||
.children("h2")
|
||||
.text(""); // removes character name from nav tabs
|
||||
clearChat(); // removes deleted char's chat
|
||||
this_chid = undefined; // prevents getCharacters from trying to load an invalid char.
|
||||
delete tag_map[avatar]; // removes deleted char's avatar from tag_map
|
||||
await getCharacters(); // gets the new list of characters (that doesn't include the deleted one)
|
||||
select_rm_info("char_delete", name); // also updates the 'deleted character' message
|
||||
printMessages(); // prints out system user's 'deleted character' message
|
||||
//console.log("#dialogue_popup_ok(del-char) >>>> saving");
|
||||
saveSettingsDebounced(); // saving settings to keep changes to variables
|
||||
},
|
||||
});
|
||||
handleDeleteCharacter(popup_type, this_chid, characters);
|
||||
}
|
||||
if (popup_type == "alternate_greeting" && menu_type !== "create") {
|
||||
createOrEditCharacter();
|
||||
|
@ -7709,13 +7760,7 @@ $(document).ready(function () {
|
|||
const preset = koboldai_settings[koboldai_setting_names[preset_settings]];
|
||||
loadKoboldSettings(preset);
|
||||
|
||||
amount_gen = preset.genamt;
|
||||
$("#amount_gen").val(amount_gen);
|
||||
$("#amount_gen_counter").text(`${amount_gen}`);
|
||||
|
||||
max_context = preset.max_length;
|
||||
$("#max_context").val(max_context);
|
||||
$("#max_context_counter").text(`${max_context}`);
|
||||
setGenerationParamsFromPreset(preset);
|
||||
|
||||
$("#range_block").find('input').prop("disabled", false);
|
||||
$("#kobold-advanced-config").find('input').prop("disabled", false);
|
||||
|
@ -8240,17 +8285,7 @@ $(document).ready(function () {
|
|||
});
|
||||
|
||||
$("#dupe_button").click(async function () {
|
||||
|
||||
const body = { avatar_url: characters[this_chid].avatar };
|
||||
const response = await fetch('/dupecharacter', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
if (response.ok) {
|
||||
toastr.success("Character Duplicated");
|
||||
getCharacters();
|
||||
}
|
||||
await DupeChar();
|
||||
});
|
||||
|
||||
$(document).on("click", ".select_chat_block, .bookmark_link, .mes_bookmark", async function () {
|
||||
|
|
|
@ -60,7 +60,10 @@ const extension_settings = {
|
|||
dice: {},
|
||||
regex: [],
|
||||
tts: {},
|
||||
sd: {},
|
||||
sd: {
|
||||
prompts: {},
|
||||
character_prompts: {},
|
||||
},
|
||||
chromadb: {},
|
||||
translate: {},
|
||||
objective: {},
|
||||
|
|
|
@ -551,10 +551,10 @@ async function onSelectInjectFile(e) {
|
|||
function doAutoAdjust(chat, maxContext) {
|
||||
console.debug('CHROMADB: Auto-adjusting sliders (messages: %o, maxContext: %o)', chat.length, maxContext);
|
||||
// Get mean message length
|
||||
const meanMessageLength = chat.reduce((acc, cur) => acc + cur.mes.length, 0) / chat.length;
|
||||
const meanMessageLength = chat.reduce((acc, cur) => acc + (cur?.mes?.length ?? 0), 0) / chat.length;
|
||||
|
||||
if (Number.isNaN(meanMessageLength)) {
|
||||
console.debug('CHROMADB: Mean message length is NaN, aborting auto-adjust');
|
||||
if (Number.isNaN(meanMessageLength) || meanMessageLength === 0) {
|
||||
console.debug('CHROMADB: Mean message length is zero or NaN, aborting auto-adjust');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -611,7 +611,7 @@ window.chromadb_interceptGeneration = async (chat, maxContext) => {
|
|||
console.debug("CHROMADB: Messages to store length vs keep context: %o vs %o", messagesToStore.length, extension_settings.chromadb.keep_context);
|
||||
await addMessages(currentChatId, messagesToStore);
|
||||
}
|
||||
|
||||
|
||||
const lastMessage = chat[chat.length - 1];
|
||||
|
||||
let queriedMessages;
|
||||
|
@ -811,15 +811,15 @@ jQuery(async () => {
|
|||
<textarea id="chromadb_custom_msg" hidden class="text_pole textarea_compact" rows="2" placeholder="${defaultSettings.chroma_default_msg}" style="height: 61px; display: none;"></textarea>
|
||||
<label for="chromadb_custom_depth" hidden><small>How deep should the memory messages be injected?: (<span id="chromadb_custom_depth_value"></span>)</small></label>
|
||||
<input id="chromadb_custom_depth" type="range" min="${defaultSettings.chroma_depth_min}" max="${defaultSettings.chroma_depth_max}" step="${defaultSettings.chroma_depth_step}" value="${defaultSettings.chroma_depth}" hidden/>
|
||||
|
||||
|
||||
<label for="chromadb_hhaa_wrapperfmt" hidden><small>Custom wrapper format:</small></label>
|
||||
<textarea id="chromadb_hhaa_wrapperfmt" hidden class="text_pole textarea_compact" rows="2" placeholder="${defaultSettings.chroma_default_hhaa_wrapper}" style="height: 61px; display: none;"></textarea>
|
||||
<label for="chromadb_hhaa_memoryfmt" hidden><small>Custom memory format:</small></label>
|
||||
<textarea id="chromadb_hhaa_memoryfmt" hidden class="text_pole textarea_compact" rows="2" placeholder="${defaultSettings.chroma_default_hhaa_memory}" style="height: 61px; display: none;"></textarea>
|
||||
<label for="chromadb_hhaa_token_limit" hidden><small>Maximum tokens allowed for memories: (<span id="chromadb_hhaa_token_limit_value"></span>)</small></label>
|
||||
<input id="chromadb_hhaa_token_limit" type="range" min="0" max="2048" step="64" value="${defaultSettings.hhaa_token_limit}" hidden/>
|
||||
|
||||
|
||||
|
||||
|
||||
<span>Memory Recall Strategy</span>
|
||||
<select id="chromadb_recall_strategy">
|
||||
<option value="original">Recall only from this chat</option>
|
||||
|
@ -834,7 +834,7 @@ jQuery(async () => {
|
|||
<input id="chromadb_keep_context" type="range" min="${defaultSettings.keep_context_min}" max="${defaultSettings.keep_context_max}" step="${defaultSettings.keep_context_step}" value="${defaultSettings.keep_context}" />
|
||||
<label for="chromadb_n_results"><small>Maximum number of ChromaDB 'memories' to inject: (<span id="chromadb_n_results_value"></span>) messages</small></label>
|
||||
<input id="chromadb_n_results" type="range" min="${defaultSettings.n_results_min}" max="${defaultSettings.n_results_max}" step="${defaultSettings.n_results_step}" value="${defaultSettings.n_results}" />
|
||||
|
||||
|
||||
<label for="chromadb_keep_context_proportion"><small>Keep (<span id="chromadb_keep_context_proportion_value"></span>%) of in-context chat messages; replace the rest with memories</small></label>
|
||||
<input id="chromadb_keep_context_proportion" type="range" min="${defaultSettings.keep_context_proportion_min}" max="${defaultSettings.keep_context_proportion_max}" step="${defaultSettings.keep_context_proportion_step}" value="${defaultSettings.keep_context_proportion}" />
|
||||
<label for="chromadb_split_length"><small>Max length for each 'memory' pulled from the current chat history: (<span id="chromadb_split_length_value"></span>) characters</small></label>
|
||||
|
|
|
@ -8,10 +8,13 @@ import {
|
|||
getRequestHeaders,
|
||||
event_types,
|
||||
eventSource,
|
||||
appendImageToMessage
|
||||
appendImageToMessage,
|
||||
generateQuietPrompt,
|
||||
this_chid,
|
||||
} from "../../../script.js";
|
||||
import { getApiUrl, getContext, extension_settings, doExtrasFetch, modules } from "../../extensions.js";
|
||||
import { stringFormat, initScrollHeight, resetScrollHeight, timestampToMoment } from "../../utils.js";
|
||||
import { selected_group } from "../../group-chats.js";
|
||||
import { stringFormat, initScrollHeight, resetScrollHeight, timestampToMoment, getCharaFilename } from "../../utils.js";
|
||||
export { MODULE_NAME };
|
||||
|
||||
// Wraps a string into monospace font-face span
|
||||
|
@ -39,6 +42,15 @@ const generationMode = {
|
|||
FREE: 6,
|
||||
}
|
||||
|
||||
const modeLabels = {
|
||||
[generationMode.CHARACTER]: 'Character ("Yourself")',
|
||||
[generationMode.FACE]: 'Portrait ("Your Face")',
|
||||
[generationMode.USER]: 'User ("Me")',
|
||||
[generationMode.SCENARIO]: 'Scenario ("The Whole Story")',
|
||||
[generationMode.NOW]: 'Last Message',
|
||||
[generationMode.RAW_LAST]: 'Raw Last Message',
|
||||
}
|
||||
|
||||
const triggerWords = {
|
||||
[generationMode.CHARACTER]: ['you'],
|
||||
[generationMode.USER]: ['me'],
|
||||
|
@ -48,7 +60,7 @@ const triggerWords = {
|
|||
[generationMode.FACE]: ['face'],
|
||||
}
|
||||
|
||||
const quietPrompts = {
|
||||
const promptTemplates = {
|
||||
/*OLD: [generationMode.CHARACTER]: "Pause your roleplay and provide comma-delimited list of phrases and keywords which describe {{char}}'s physical appearance and clothing. Ignore {{char}}'s personality traits, and chat history when crafting this description. End your response once the comma-delimited list is complete. Do not roleplay when writing this description, and do not attempt to continue the story.", */
|
||||
[generationMode.CHARACTER]: "[In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,']",
|
||||
//face-specific prompt
|
||||
|
@ -134,6 +146,8 @@ const defaultSettings = {
|
|||
|
||||
// Refine mode
|
||||
refine_mode: false,
|
||||
|
||||
prompts: promptTemplates,
|
||||
}
|
||||
|
||||
async function loadSettings() {
|
||||
|
@ -141,6 +155,14 @@ async function loadSettings() {
|
|||
Object.assign(extension_settings.sd, defaultSettings);
|
||||
}
|
||||
|
||||
if (extension_settings.sd.prompts === undefined) {
|
||||
extension_settings.sd.prompts = promptTemplates;
|
||||
}
|
||||
|
||||
if (extension_settings.sd.character_prompts === undefined) {
|
||||
extension_settings.sd.character_prompts = {};
|
||||
}
|
||||
|
||||
$('#sd_scale').val(extension_settings.sd.scale).trigger('input');
|
||||
$('#sd_steps').val(extension_settings.sd.steps).trigger('input');
|
||||
$('#sd_prompt_prefix').val(extension_settings.sd.prompt_prefix).trigger('input');
|
||||
|
@ -154,9 +176,104 @@ async function loadSettings() {
|
|||
$('#sd_enable_hr').prop('checked', extension_settings.sd.enable_hr);
|
||||
$('#sd_refine_mode').prop('checked', extension_settings.sd.refine_mode);
|
||||
|
||||
addPromptTemplates();
|
||||
|
||||
await Promise.all([loadSamplers(), loadModels()]);
|
||||
}
|
||||
|
||||
function addPromptTemplates() {
|
||||
$('#sd_prompt_templates').empty();
|
||||
|
||||
for (const [name, prompt] of Object.entries(extension_settings.sd.prompts)) {
|
||||
const label = $('<label></label>')
|
||||
.text(modeLabels[name])
|
||||
.attr('for', `sd_prompt_${name}`);
|
||||
const textarea = $('<textarea></textarea>')
|
||||
.addClass('textarea_compact text_pole')
|
||||
.attr('id', `sd_prompt_${name}`)
|
||||
.attr('rows', 6)
|
||||
.val(prompt).on('input', () => {
|
||||
extension_settings.sd.prompts[name] = textarea.val();
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
const button = $('<button></button>')
|
||||
.addClass('menu_button fa-solid fa-undo')
|
||||
.attr('title', 'Restore default')
|
||||
.on('click', () => {
|
||||
textarea.val(promptTemplates[name]);
|
||||
extension_settings.sd.prompts[name] = promptTemplates[name];
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
const container = $('<div></div>')
|
||||
.addClass('title_restorable')
|
||||
.append(label)
|
||||
.append(button)
|
||||
$('#sd_prompt_templates').append(container);
|
||||
$('#sd_prompt_templates').append(textarea);
|
||||
}
|
||||
}
|
||||
|
||||
async function refinePrompt(prompt) {
|
||||
if (extension_settings.sd.refine_mode) {
|
||||
const refinedPrompt = await callPopup('<h3>Review and edit the prompt:</h3>Press "Cancel" to abort the image generation.', 'input', prompt, { rows: 5, okButton: 'Generate' });
|
||||
|
||||
if (refinedPrompt) {
|
||||
return refinedPrompt;
|
||||
} else {
|
||||
throw new Error('Generation aborted by user.');
|
||||
}
|
||||
}
|
||||
|
||||
return prompt;
|
||||
}
|
||||
|
||||
function onChatChanged() {
|
||||
if (this_chid === undefined || selected_group) {
|
||||
$('#sd_character_prompt_block').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#sd_character_prompt_block').show();
|
||||
const key = getCharaFilename(this_chid);
|
||||
$('#sd_character_prompt').val(key ? (extension_settings.sd.character_prompts[key] || '') : '');
|
||||
}
|
||||
|
||||
function onCharacterPromptInput() {
|
||||
const key = getCharaFilename(this_chid);
|
||||
extension_settings.sd.character_prompts[key] = $('#sd_character_prompt').val();
|
||||
resetScrollHeight($(this));
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
function getCharacterPrefix() {
|
||||
if (selected_group) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const key = getCharaFilename(this_chid);
|
||||
|
||||
if (key) {
|
||||
return extension_settings.sd.character_prompts[key] || '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function combinePrefixes(str1, str2) {
|
||||
if (!str2) {
|
||||
return str1;
|
||||
}
|
||||
|
||||
// Remove leading/trailing white spaces and commas from the strings
|
||||
str1 = str1.trim().replace(/^,|,$/g, '');
|
||||
str2 = str2.trim().replace(/^,|,$/g, '');
|
||||
|
||||
// Combine the strings with a comma between them
|
||||
var result = `${str1}, ${str2},`;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function onRefineModeInput() {
|
||||
extension_settings.sd.refine_mode = !!$('#sd_refine_mode').prop('checked');
|
||||
saveSettingsDebounced();
|
||||
|
@ -383,7 +500,7 @@ function getQuietPrompt(mode, trigger) {
|
|||
return trigger;
|
||||
}
|
||||
|
||||
return substituteParams(stringFormat(quietPrompts[mode], trigger));
|
||||
return substituteParams(stringFormat(extension_settings.sd.prompts[mode], trigger));
|
||||
}
|
||||
|
||||
function processReply(str) {
|
||||
|
@ -475,31 +592,16 @@ async function getPrompt(generationType, message, trigger, quiet_prompt) {
|
|||
break;
|
||||
}
|
||||
|
||||
if (generationType !== generationMode.FREE) {
|
||||
prompt = await refinePrompt(prompt);
|
||||
}
|
||||
|
||||
return prompt;
|
||||
}
|
||||
|
||||
async function generatePrompt(quiet_prompt) {
|
||||
let reply = processReply(await new Promise(
|
||||
async function promptPromise(resolve, reject) {
|
||||
try {
|
||||
await getContext().generate('quiet', { resolve, reject, quiet_prompt, force_name2: true, });
|
||||
}
|
||||
catch {
|
||||
reject();
|
||||
}
|
||||
}));
|
||||
|
||||
if (extension_settings.sd.refine_mode) {
|
||||
const refinedPrompt = await callPopup('<h3>Review and edit the generated prompt:</h3>Press "Cancel" to abort the image generation.', 'input', reply, { rows: 5, okButton: 'Generate' });
|
||||
|
||||
if (refinedPrompt) {
|
||||
reply = refinedPrompt;
|
||||
} else {
|
||||
throw new Error('Generation aborted by user.');
|
||||
}
|
||||
}
|
||||
|
||||
return reply;
|
||||
const reply = await generateQuietPrompt(quiet_prompt);
|
||||
return processReply(reply);
|
||||
}
|
||||
|
||||
async function sendGenerationRequest(prompt, callback) {
|
||||
|
@ -524,7 +626,7 @@ async function generateExtrasImage(prompt, callback) {
|
|||
scale: extension_settings.sd.scale,
|
||||
width: extension_settings.sd.width,
|
||||
height: extension_settings.sd.height,
|
||||
prompt_prefix: extension_settings.sd.prompt_prefix,
|
||||
prompt_prefix: combinePrefixes(extension_settings.sd.prompt_prefix, getCharacterPrefix()),
|
||||
negative_prompt: extension_settings.sd.negative_prompt,
|
||||
restore_faces: !!extension_settings.sd.restore_faces,
|
||||
enable_hr: !!extension_settings.sd.enable_hr,
|
||||
|
@ -552,7 +654,7 @@ async function generateHordeImage(prompt, callback) {
|
|||
scale: extension_settings.sd.scale,
|
||||
width: extension_settings.sd.width,
|
||||
height: extension_settings.sd.height,
|
||||
prompt_prefix: extension_settings.sd.prompt_prefix,
|
||||
prompt_prefix: combinePrefixes(extension_settings.sd.prompt_prefix, getCharacterPrefix()),
|
||||
negative_prompt: extension_settings.sd.negative_prompt,
|
||||
model: extension_settings.sd.model,
|
||||
nsfw: extension_settings.sd.horde_nsfw,
|
||||
|
@ -690,7 +792,9 @@ async function sdMessageButton(e) {
|
|||
try {
|
||||
setBusyIcon(true);
|
||||
if (hasSavedImage) {
|
||||
const prompt = message?.extra?.title;
|
||||
const prompt = await refinePrompt(message.extra.title);
|
||||
message.extra.title = prompt;
|
||||
|
||||
console.log('Regenerating an image, using existing prompt:', prompt);
|
||||
await sendGenerationRequest(prompt, saveGeneratedImage);
|
||||
}
|
||||
|
@ -763,60 +867,74 @@ jQuery(async () => {
|
|||
<div class="sd_settings">
|
||||
<div class="inline-drawer">
|
||||
<div class="inline-drawer-toggle inline-drawer-header">
|
||||
<b>Stable Diffusion</b>
|
||||
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||
<b>Stable Diffusion</b>
|
||||
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||
</div>
|
||||
<div class="inline-drawer-content">
|
||||
<small><i>Use slash commands or the bottom Paintbrush button to generate images. Type <span class="monospace">/help</span> in chat for more details</i></small>
|
||||
<br>
|
||||
<small><i>Hint: Save an API key in Horde KoboldAI API settings to use it here.</i></small>
|
||||
<label for="sd_refine_mode" class="checkbox_label" title="Allow to edit prompts manually before sending them to generation API">
|
||||
<input id="sd_refine_mode" type="checkbox" />
|
||||
Edit prompts before generation
|
||||
</label>
|
||||
<div class="flex-container flexGap5 marginTop10 margin-bot-10px">
|
||||
<label class="checkbox_label">
|
||||
<input id="sd_horde" type="checkbox" />
|
||||
Use Stable Horde
|
||||
</label>
|
||||
<label style="margin-left:1em;" class="checkbox_label">
|
||||
<input id="sd_horde_nsfw" type="checkbox" />
|
||||
Allow NSFW images from Horde
|
||||
</label>
|
||||
</div>
|
||||
<label for="sd_scale">CFG Scale (<span id="sd_scale_value"></span>)</label>
|
||||
<input id="sd_scale" type="range" min="${defaultSettings.scale_min}" max="${defaultSettings.scale_max}" step="${defaultSettings.scale_step}" value="${defaultSettings.scale}" />
|
||||
<label for="sd_steps">Sampling steps (<span id="sd_steps_value"></span>)</label>
|
||||
<input id="sd_steps" type="range" min="${defaultSettings.steps_min}" max="${defaultSettings.steps_max}" step="${defaultSettings.steps_step}" value="${defaultSettings.steps}" />
|
||||
<label for="sd_width">Width (<span id="sd_width_value"></span>)</label>
|
||||
<input id="sd_width" type="range" max="${defaultSettings.dimension_max}" min="${defaultSettings.dimension_min}" step="${defaultSettings.dimension_step}" value="${defaultSettings.width}" />
|
||||
<label for="sd_height">Height (<span id="sd_height_value"></span>)</label>
|
||||
<input id="sd_height" type="range" max="${defaultSettings.dimension_max}" min="${defaultSettings.dimension_min}" step="${defaultSettings.dimension_step}" value="${defaultSettings.height}" />
|
||||
<div><small>Only for Horde or remote Stable Diffusion Web UI:</small></div>
|
||||
<div class="flex-container marginTop10 margin-bot-10px">
|
||||
<label class="flex1 checkbox_label">
|
||||
<input id="sd_restore_faces" type="checkbox" />
|
||||
Restore Faces
|
||||
</label>
|
||||
<label class="flex1 checkbox_label">
|
||||
<input id="sd_enable_hr" type="checkbox" />
|
||||
Hires. Fix
|
||||
</label>
|
||||
</div>
|
||||
<label for="sd_model">Stable Diffusion model</label>
|
||||
<select id="sd_model"></select>
|
||||
<label for="sd_sampler">Sampling method</label>
|
||||
<select id="sd_sampler"></select>
|
||||
<div class="flex-container flexGap5 margin-bot-10px">
|
||||
<label class="checkbox_label">
|
||||
<input id="sd_horde_karras" type="checkbox" />
|
||||
Karras (only for Horde, not all samplers supported)
|
||||
</label>
|
||||
</div>
|
||||
<label for="sd_prompt_prefix">Common prompt prefix</label>
|
||||
<textarea id="sd_prompt_prefix" class="text_pole textarea_compact" rows="3"></textarea>
|
||||
<div id="sd_character_prompt_block">
|
||||
<label for="sd_character_prompt">Character-specific prompt prefix</label>
|
||||
<small>Won't be used in groups.</small>
|
||||
<textarea id="sd_character_prompt" class="text_pole textarea_compact" rows="3" placeholder="Any characteristics that describe the currently selected character. Will be added after a common prefix. Example: female, green eyes, brown hair, pink shirt"></textarea>
|
||||
</div>
|
||||
<label for="sd_negative_prompt">Negative prompt</label>
|
||||
<textarea id="sd_negative_prompt" class="text_pole textarea_compact" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-drawer-content">
|
||||
<small><i>Use slash commands or the bottom Paintbrush button to generate images. Type <span class="monospace">/help</span> in chat for more details</i></small>
|
||||
<br>
|
||||
<small><i>Hint: Save an API key in Horde KoboldAI API settings to use it here.</i></small>
|
||||
<label for="sd_refine_mode" class="checkbox_label" title="Allow to edit prompts manually before sending them to generation API">
|
||||
<input id="sd_refine_mode" type="checkbox" />
|
||||
Edit prompts before generation
|
||||
</label>
|
||||
<div class="flex-container flexGap5 marginTop10 margin-bot-10px">
|
||||
<label class="checkbox_label">
|
||||
<input id="sd_horde" type="checkbox" />
|
||||
Use Stable Horde
|
||||
</label>
|
||||
<label style="margin-left:1em;" class="checkbox_label">
|
||||
<input id="sd_horde_nsfw" type="checkbox" />
|
||||
Allow NSFW images from Horde
|
||||
</label>
|
||||
<div class="inline-drawer">
|
||||
<div class="inline-drawer-toggle inline-drawer-header">
|
||||
<b>SD Prompt Templates</b>
|
||||
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||
</div>
|
||||
<label for="sd_scale">CFG Scale (<span id="sd_scale_value"></span>)</label>
|
||||
<input id="sd_scale" type="range" min="${defaultSettings.scale_min}" max="${defaultSettings.scale_max}" step="${defaultSettings.scale_step}" value="${defaultSettings.scale}" />
|
||||
<label for="sd_steps">Sampling steps (<span id="sd_steps_value"></span>)</label>
|
||||
<input id="sd_steps" type="range" min="${defaultSettings.steps_min}" max="${defaultSettings.steps_max}" step="${defaultSettings.steps_step}" value="${defaultSettings.steps}" />
|
||||
<label for="sd_width">Width (<span id="sd_width_value"></span>)</label>
|
||||
<input id="sd_width" type="range" max="${defaultSettings.dimension_max}" min="${defaultSettings.dimension_min}" step="${defaultSettings.dimension_step}" value="${defaultSettings.width}" />
|
||||
<label for="sd_height">Height (<span id="sd_height_value"></span>)</label>
|
||||
<input id="sd_height" type="range" max="${defaultSettings.dimension_max}" min="${defaultSettings.dimension_min}" step="${defaultSettings.dimension_step}" value="${defaultSettings.height}" />
|
||||
<div><small>Only for Horde or remote Stable Diffusion Web UI:</small></div>
|
||||
<div class="flex-container marginTop10 margin-bot-10px">
|
||||
<label class="flex1 checkbox_label">
|
||||
<input id="sd_restore_faces" type="checkbox" />
|
||||
Restore Faces
|
||||
</label>
|
||||
<label class="flex1 checkbox_label">
|
||||
<input id="sd_enable_hr" type="checkbox" />
|
||||
Hires. Fix
|
||||
</label>
|
||||
<div id="sd_prompt_templates" class="inline-drawer-content">
|
||||
</div>
|
||||
<label for="sd_model">Stable Diffusion model</label>
|
||||
<select id="sd_model"></select>
|
||||
<label for="sd_sampler">Sampling method</label>
|
||||
<select id="sd_sampler"></select>
|
||||
<div class="flex-container flexGap5 margin-bot-10px">
|
||||
<label class="checkbox_label">
|
||||
<input id="sd_horde_karras" type="checkbox" />
|
||||
Karras (only for Horde, not all samplers supported)
|
||||
</label>
|
||||
</div>
|
||||
<label for="sd_prompt_prefix">Generated prompt prefix</label>
|
||||
<textarea id="sd_prompt_prefix" class="text_pole textarea_compact" rows="2"></textarea>
|
||||
<label for="sd_negative_prompt">Negative prompt</label>
|
||||
<textarea id="sd_negative_prompt" class="text_pole textarea_compact" rows="2"></textarea>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
|
@ -835,16 +953,21 @@ jQuery(async () => {
|
|||
$('#sd_restore_faces').on('input', onRestoreFacesInput);
|
||||
$('#sd_enable_hr').on('input', onHighResFixInput);
|
||||
$('#sd_refine_mode').on('input', onRefineModeInput);
|
||||
$('#sd_character_prompt').on('input', onCharacterPromptInput);
|
||||
$('#sd_character_prompt_block').hide();
|
||||
|
||||
$('.sd_settings .inline-drawer-toggle').on('click', function () {
|
||||
initScrollHeight($("#sd_prompt_prefix"));
|
||||
initScrollHeight($("#sd_negative_prompt"));
|
||||
initScrollHeight($("#sd_character_prompt"));
|
||||
})
|
||||
|
||||
eventSource.on(event_types.EXTRAS_CONNECTED, async () => {
|
||||
await Promise.all([loadSamplers(), loadModels()]);
|
||||
});
|
||||
|
||||
eventSource.on(event_types.CHAT_CHANGED, onChatChanged);
|
||||
|
||||
await loadSettings();
|
||||
$('body').addClass('sd');
|
||||
});
|
||||
|
|
|
@ -24,6 +24,6 @@
|
|||
}
|
||||
|
||||
#sd_dropdown {
|
||||
z-index: 3000;
|
||||
z-index: 30000;
|
||||
backdrop-filter: blur(--SmartThemeBlurStrength);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,13 +11,18 @@ export {
|
|||
};
|
||||
|
||||
const nai_settings = {
|
||||
temp_novel: 0.5,
|
||||
rep_pen_novel: 1,
|
||||
rep_pen_size_novel: 100,
|
||||
rep_pen_slope_novel: 0,
|
||||
rep_pen_freq_novel: 0,
|
||||
rep_pen_presence_novel: 0,
|
||||
tail_free_sampling_novel: 0.68,
|
||||
temperature: 0.5,
|
||||
repetition_penalty: 1,
|
||||
repetition_penalty_range: 100,
|
||||
repetition_penalty_slope: 0,
|
||||
repetition_penalty_frequency: 0,
|
||||
repetition_penalty_presence: 0,
|
||||
tail_free_sampling: 0.68,
|
||||
top_k: 0,
|
||||
top_p: 1,
|
||||
top_a: 1,
|
||||
typical_p: 1,
|
||||
min_length: 0,
|
||||
model_novel: "euterpe-v2",
|
||||
preset_settings_novel: "Classic-Euterpe",
|
||||
streaming_novel: false,
|
||||
|
@ -45,13 +50,18 @@ function loadNovelPreset(preset) {
|
|||
$("#max_context_counter").text(`${preset.max_context}`);
|
||||
$("#rep_pen_size_novel").attr('max', preset.max_context);
|
||||
|
||||
nai_settings.temp_novel = preset.temperature;
|
||||
nai_settings.rep_pen_novel = preset.repetition_penalty;
|
||||
nai_settings.rep_pen_size_novel = preset.repetition_penalty_range;
|
||||
nai_settings.rep_pen_slope_novel = preset.repetition_penalty_slope;
|
||||
nai_settings.rep_pen_freq_novel = preset.repetition_penalty_frequency;
|
||||
nai_settings.rep_pen_presence_novel = preset.repetition_penalty_presence;
|
||||
nai_settings.tail_free_sampling_novel = preset.tail_free_sampling;
|
||||
nai_settings.temperature = preset.temperature;
|
||||
nai_settings.repetition_penalty = preset.repetition_penalty;
|
||||
nai_settings.repetition_penalty_range = preset.repetition_penalty_range;
|
||||
nai_settings.repetition_penalty_slope = preset.repetition_penalty_slope;
|
||||
nai_settings.repetition_penalty_frequency = preset.repetition_penalty_frequency;
|
||||
nai_settings.repetition_penalty_presence = preset.repetition_penalty_presence;
|
||||
nai_settings.tail_free_sampling = preset.tail_free_sampling;
|
||||
nai_settings.top_k = preset.top_k;
|
||||
nai_settings.top_p = preset.top_p;
|
||||
nai_settings.top_a = preset.top_a;
|
||||
nai_settings.typical_p = preset.typical_p;
|
||||
nai_settings.min_length = preset.min_length;
|
||||
loadNovelSettingsUi(nai_settings);
|
||||
}
|
||||
|
||||
|
@ -59,33 +69,58 @@ function loadNovelSettings(settings) {
|
|||
//load the rest of the Novel settings without any checks
|
||||
nai_settings.model_novel = settings.model_novel;
|
||||
$(`#model_novel_select option[value=${nai_settings.model_novel}]`).attr("selected", true);
|
||||
$('#model_novel_select').val(nai_settings.model_novel);
|
||||
|
||||
nai_settings.temp_novel = settings.temp_novel;
|
||||
nai_settings.rep_pen_novel = settings.rep_pen_novel;
|
||||
nai_settings.rep_pen_size_novel = settings.rep_pen_size_novel;
|
||||
nai_settings.rep_pen_slope_novel = settings.rep_pen_slope_novel;
|
||||
nai_settings.rep_pen_freq_novel = settings.rep_pen_freq_novel;
|
||||
nai_settings.rep_pen_presence_novel = settings.rep_pen_presence_novel;
|
||||
nai_settings.tail_free_sampling_novel = settings.tail_free_sampling_novel;
|
||||
nai_settings.preset_settings_novel = settings.preset_settings_novel;
|
||||
nai_settings.temperature = settings.temperature;
|
||||
nai_settings.repetition_penalty = settings.repetition_penalty;
|
||||
nai_settings.repetition_penalty_range = settings.repetition_penalty_range;
|
||||
nai_settings.repetition_penalty_slope = settings.repetition_penalty_slope;
|
||||
nai_settings.repetition_penalty_frequency = settings.repetition_penalty_frequency;
|
||||
nai_settings.repetition_penalty_presence = settings.repetition_penalty_presence;
|
||||
nai_settings.tail_free_sampling = settings.tail_free_sampling;
|
||||
nai_settings.top_k = settings.top_k;
|
||||
nai_settings.top_p = settings.top_p;
|
||||
nai_settings.top_a = settings.top_a;
|
||||
nai_settings.typical_p = settings.typical_p;
|
||||
nai_settings.min_length = settings.min_length;
|
||||
nai_settings.streaming_novel = !!settings.streaming_novel;
|
||||
loadNovelSettingsUi(nai_settings);
|
||||
|
||||
// reload the preset to migrate any new settings
|
||||
for (const key of Object.keys(nai_settings)) {
|
||||
if (typeof nai_settings[key] === 'number' && Number.isNaN(nai_settings[key])) {
|
||||
$("#settings_perset_novel").trigger("change");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadNovelSettingsUi(ui_settings) {
|
||||
$("#temp_novel").val(ui_settings.temp_novel);
|
||||
$("#temp_counter_novel").text(Number(ui_settings.temp_novel).toFixed(2));
|
||||
$("#rep_pen_novel").val(ui_settings.rep_pen_novel);
|
||||
$("#rep_pen_counter_novel").text(Number(ui_settings.rep_pen_novel).toFixed(2));
|
||||
$("#rep_pen_size_novel").val(ui_settings.rep_pen_size_novel);
|
||||
$("#rep_pen_size_counter_novel").text(Number(ui_settings.rep_pen_size_novel).toFixed(0));
|
||||
$("#rep_pen_slope_novel").val(ui_settings.rep_pen_slope_novel);
|
||||
$("#rep_pen_slope_counter_novel").text(Number(`${ui_settings.rep_pen_slope_novel}`).toFixed(2));
|
||||
$("#rep_pen_freq_novel").val(ui_settings.rep_pen_freq_novel);
|
||||
$("#rep_pen_freq_counter_novel").text(Number(ui_settings.rep_pen_freq_novel).toFixed(5));
|
||||
$("#rep_pen_presence_novel").val(ui_settings.rep_pen_presence_novel);
|
||||
$("#rep_pen_presence_counter_novel").text(Number(ui_settings.rep_pen_presence_novel).toFixed(3));
|
||||
$("#tail_free_sampling_novel").val(ui_settings.tail_free_sampling_novel);
|
||||
$("#tail_free_sampling_counter_novel").text(Number(ui_settings.tail_free_sampling_novel).toFixed(3));
|
||||
$("#temp_novel").val(ui_settings.temperature);
|
||||
$("#temp_counter_novel").text(Number(ui_settings.temperature).toFixed(2));
|
||||
$("#rep_pen_novel").val(ui_settings.repetition_penalty);
|
||||
$("#rep_pen_counter_novel").text(Number(ui_settings.repetition_penalty).toFixed(2));
|
||||
$("#rep_pen_size_novel").val(ui_settings.repetition_penalty_range);
|
||||
$("#rep_pen_size_counter_novel").text(Number(ui_settings.repetition_penalty_range).toFixed(0));
|
||||
$("#rep_pen_slope_novel").val(ui_settings.repetition_penalty_slope);
|
||||
$("#rep_pen_slope_counter_novel").text(Number(`${ui_settings.repetition_penalty_slope}`).toFixed(2));
|
||||
$("#rep_pen_freq_novel").val(ui_settings.repetition_penalty_frequency);
|
||||
$("#rep_pen_freq_counter_novel").text(Number(ui_settings.repetition_penalty_frequency).toFixed(5));
|
||||
$("#rep_pen_presence_novel").val(ui_settings.repetition_penalty_presence);
|
||||
$("#rep_pen_presence_counter_novel").text(Number(ui_settings.repetition_penalty_presence).toFixed(3));
|
||||
$("#tail_free_sampling_novel").val(ui_settings.tail_free_sampling);
|
||||
$("#tail_free_sampling_counter_novel").text(Number(ui_settings.tail_free_sampling).toFixed(3));
|
||||
$("#top_k_novel").val(ui_settings.top_k);
|
||||
$("#top_k_counter_novel").text(Number(ui_settings.top_k).toFixed(0));
|
||||
$("#top_p_novel").val(ui_settings.top_p);
|
||||
$("#top_p_counter_novel").text(Number(ui_settings.top_p).toFixed(2));
|
||||
$("#top_a_novel").val(ui_settings.top_a);
|
||||
$("#top_a_counter_novel").text(Number(ui_settings.top_a).toFixed(2));
|
||||
$("#typical_p_novel").val(ui_settings.typical_p);
|
||||
$("#typical_p_counter_novel").text(Number(ui_settings.typical_p).toFixed(2));
|
||||
$("#min_length_novel").val(ui_settings.min_length);
|
||||
$("#min_length_counter_novel").text(Number(ui_settings.min_length).toFixed(0));
|
||||
|
||||
$("#streaming_novel").prop('checked', ui_settings.streaming_novel);
|
||||
}
|
||||
|
||||
|
@ -94,43 +129,73 @@ const sliders = [
|
|||
sliderId: "#temp_novel",
|
||||
counterId: "#temp_counter_novel",
|
||||
format: (val) => Number(val).toFixed(2),
|
||||
setValue: (val) => { nai_settings.temp_novel = Number(val).toFixed(2); },
|
||||
setValue: (val) => { nai_settings.temperature = Number(val).toFixed(2); },
|
||||
},
|
||||
{
|
||||
sliderId: "#rep_pen_novel",
|
||||
counterId: "#rep_pen_counter_novel",
|
||||
format: (val) => Number(val).toFixed(2),
|
||||
setValue: (val) => { nai_settings.rep_pen_novel = Number(val).toFixed(2); },
|
||||
setValue: (val) => { nai_settings.repetition_penalty = Number(val).toFixed(2); },
|
||||
},
|
||||
{
|
||||
sliderId: "#rep_pen_size_novel",
|
||||
counterId: "#rep_pen_size_counter_novel",
|
||||
format: (val) => `${val}`,
|
||||
setValue: (val) => { nai_settings.rep_pen_size_novel = Number(val).toFixed(0); },
|
||||
setValue: (val) => { nai_settings.repetition_penalty_range = Number(val).toFixed(0); },
|
||||
},
|
||||
{
|
||||
sliderId: "#rep_pen_slope_novel",
|
||||
counterId: "#rep_pen_slope_counter_novel",
|
||||
format: (val) => `${val}`,
|
||||
setValue: (val) => { nai_settings.rep_pen_slope_novel = Number(val).toFixed(2); },
|
||||
setValue: (val) => { nai_settings.repetition_penalty_slope = Number(val).toFixed(2); },
|
||||
},
|
||||
{
|
||||
sliderId: "#rep_pen_freq_novel",
|
||||
counterId: "#rep_pen_freq_counter_novel",
|
||||
format: (val) => `${val}`,
|
||||
setValue: (val) => { nai_settings.rep_pen_freq_novel = Number(val).toFixed(5); },
|
||||
setValue: (val) => { nai_settings.repetition_penalty_frequency = Number(val).toFixed(5); },
|
||||
},
|
||||
{
|
||||
sliderId: "#rep_pen_presence_novel",
|
||||
counterId: "#rep_pen_presence_counter_novel",
|
||||
format: (val) => `${val}`,
|
||||
setValue: (val) => { nai_settings.rep_pen_presence_novel = Number(val).toFixed(3); },
|
||||
setValue: (val) => { nai_settings.repetition_penalty_presence = Number(val).toFixed(3); },
|
||||
},
|
||||
{
|
||||
sliderId: "#tail_free_sampling_novel",
|
||||
counterId: "#tail_free_sampling_counter_novel",
|
||||
format: (val) => `${val}`,
|
||||
setValue: (val) => { nai_settings.tail_free_sampling_novel = Number(val).toFixed(3); },
|
||||
setValue: (val) => { nai_settings.tail_free_sampling = Number(val).toFixed(3); },
|
||||
},
|
||||
{
|
||||
sliderId: "#top_k_novel",
|
||||
counterId: "#top_k_counter_novel",
|
||||
format: (val) => `${val}`,
|
||||
setValue: (val) => { nai_settings.top_k = Number(val).toFixed(0); },
|
||||
},
|
||||
{
|
||||
sliderId: "#top_p_novel",
|
||||
counterId: "#top_p_counter_novel",
|
||||
format: (val) => Number(val).toFixed(2),
|
||||
setValue: (val) => { nai_settings.top_p = Number(val).toFixed(2); },
|
||||
},
|
||||
{
|
||||
sliderId: "#top_a_novel",
|
||||
counterId: "#top_a_counter_novel",
|
||||
format: (val) => Number(val).toFixed(2),
|
||||
setValue: (val) => { nai_settings.top_a = Number(val).toFixed(2); },
|
||||
},
|
||||
{
|
||||
sliderId: "#typical_p_novel",
|
||||
counterId: "#typical_p_counter_novel",
|
||||
format: (val) => Number(val).toFixed(2),
|
||||
setValue: (val) => { nai_settings.typical_p = Number(val).toFixed(2); },
|
||||
},
|
||||
{
|
||||
sliderId: "#min_length_novel",
|
||||
counterId: "#min_length_counter_novel",
|
||||
format: (val) => `${val}`,
|
||||
setValue: (val) => { nai_settings.min_length = Number(val).toFixed(0); },
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -139,19 +204,19 @@ export function getNovelGenerationData(finalPromt, this_settings, this_amount_ge
|
|||
"input": finalPromt,
|
||||
"model": nai_settings.model_novel,
|
||||
"use_string": true,
|
||||
"temperature": parseFloat(nai_settings.temp_novel),
|
||||
"temperature": parseFloat(nai_settings.temperature),
|
||||
"max_length": this_amount_gen, // this_settings.max_length, // <= why?
|
||||
"min_length": this_settings.min_length,
|
||||
"tail_free_sampling": parseFloat(nai_settings.tail_free_sampling_novel),
|
||||
"repetition_penalty": parseFloat(nai_settings.rep_pen_novel),
|
||||
"repetition_penalty_range": parseInt(nai_settings.rep_pen_size_novel),
|
||||
"repetition_penalty_slope": parseFloat(nai_settings.rep_pen_slope_novel),
|
||||
"repetition_penalty_frequency": parseFloat(nai_settings.rep_pen_freq_novel),
|
||||
"repetition_penalty_presence": parseFloat(nai_settings.rep_pen_presence_novel),
|
||||
"top_a": this_settings.top_a,
|
||||
"top_p": this_settings.top_p,
|
||||
"top_k": this_settings.top_k,
|
||||
"typical_p": this_settings.typical_p,
|
||||
"min_length": parseInt(nai_settings.min_length),
|
||||
"tail_free_sampling": parseFloat(nai_settings.tail_free_sampling),
|
||||
"repetition_penalty": parseFloat(nai_settings.repetition_penalty),
|
||||
"repetition_penalty_range": parseInt(nai_settings.repetition_penalty_range),
|
||||
"repetition_penalty_slope": parseFloat(nai_settings.repetition_penalty_slope),
|
||||
"repetition_penalty_frequency": parseFloat(nai_settings.repetition_penalty_frequency),
|
||||
"repetition_penalty_presence": parseFloat(nai_settings.repetition_penalty_presence),
|
||||
"top_a": parseFloat(nai_settings.top_a),
|
||||
"top_p": parseFloat(nai_settings.top_p),
|
||||
"top_k": parseInt(nai_settings.top_k),
|
||||
"typical_p": parseFloat(nai_settings.typical_p),
|
||||
//"stop_sequences": {{187}},
|
||||
//bad_words_ids = {{50256}, {0}, {1}};
|
||||
"generate_until_sentence": true,
|
||||
|
@ -212,7 +277,7 @@ $(document).ready(function () {
|
|||
const value = $(this).val();
|
||||
const formattedValue = slider.format(value);
|
||||
slider.setValue(value);
|
||||
$(slider.counterId).html(formattedValue);
|
||||
$(slider.counterId).text(formattedValue);
|
||||
console.log('saving');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
|
|
@ -43,7 +43,7 @@ export {
|
|||
send_on_enter_options,
|
||||
};
|
||||
|
||||
const MAX_CONTEXT_DEFAULT = 4096;
|
||||
export const MAX_CONTEXT_DEFAULT = 4096;
|
||||
const MAX_CONTEXT_UNLOCKED = 65536;
|
||||
|
||||
const avatar_styles = {
|
||||
|
@ -534,6 +534,11 @@ async function applyTheme(name) {
|
|||
{
|
||||
key: 'chat_width',
|
||||
action: async () => {
|
||||
// If chat width is not set, set it to 50
|
||||
if (!power_user.chat_width) {
|
||||
power_user.chat_width = 50;
|
||||
}
|
||||
|
||||
localStorage.setItem(storage_keys.chat_width, power_user.chat_width);
|
||||
applyChatWidth();
|
||||
}
|
||||
|
@ -660,6 +665,10 @@ function loadPowerUserSettings(settings, data) {
|
|||
power_user.waifuMode = false;
|
||||
}
|
||||
|
||||
if (power_user.chat_width === '') {
|
||||
power_user.chat_width = 50;
|
||||
}
|
||||
|
||||
$('#trim_spaces').prop("checked", power_user.trim_spaces);
|
||||
$('#continue_on_send').prop("checked", power_user.continue_on_send);
|
||||
$('#auto_swipe').prop("checked", power_user.auto_swipe);
|
||||
|
@ -1151,10 +1160,10 @@ async function resetMovablePanels(type) {
|
|||
//if happening as part of preset application, do it quietly.
|
||||
if (type === 'quiet') {
|
||||
return
|
||||
//if happening due to resize, tell user.
|
||||
//if happening due to resize, tell user.
|
||||
} else if (type === 'resize') {
|
||||
toastr.warning('Panel positions reset due to zoom/resize');
|
||||
//if happening due to manual button press
|
||||
//if happening due to manual button press
|
||||
} else {
|
||||
toastr.success('Panel positions reset');
|
||||
}
|
||||
|
@ -1173,7 +1182,7 @@ function doNewChat() {
|
|||
|
||||
function doRandomChat() {
|
||||
resetSelectedGroup();
|
||||
setCharacterId(Math.floor(Math.random() * characters.length));
|
||||
setCharacterId(Math.floor(Math.random() * characters.length).toString());
|
||||
setTimeout(() => {
|
||||
reloadCurrentChat();
|
||||
}, 1);
|
||||
|
|
|
@ -0,0 +1,351 @@
|
|||
import {
|
||||
amount_gen,
|
||||
callPopup,
|
||||
characters,
|
||||
eventSource,
|
||||
event_types,
|
||||
getRequestHeaders,
|
||||
koboldai_setting_names,
|
||||
koboldai_settings,
|
||||
main_api,
|
||||
max_context,
|
||||
nai_settings,
|
||||
novelai_setting_names,
|
||||
novelai_settings,
|
||||
saveSettingsDebounced,
|
||||
this_chid,
|
||||
} from "../script.js";
|
||||
import { groups, selected_group } from "./group-chats.js";
|
||||
import { kai_settings } from "./kai-settings.js";
|
||||
import {
|
||||
textgenerationwebui_preset_names,
|
||||
textgenerationwebui_presets,
|
||||
textgenerationwebui_settings,
|
||||
} from "./textgen-settings.js";
|
||||
import { download, parseJsonFile, waitUntilCondition } from "./utils.js";
|
||||
|
||||
const presetManagers = {};
|
||||
|
||||
function autoSelectPreset() {
|
||||
const presetManager = getPresetManager();
|
||||
|
||||
if (!presetManager) {
|
||||
console.debug(`Preset Manager not found for API: ${main_api}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const name = selected_group ? groups.find(x => x.id == selected_group)?.name : characters[this_chid]?.name;
|
||||
|
||||
if (!name) {
|
||||
console.debug(`Preset candidate not found for API: ${main_api}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const preset = presetManager.findPreset(name);
|
||||
const selectedPreset = presetManager.getSelectedPreset();
|
||||
|
||||
if (preset === selectedPreset) {
|
||||
console.debug(`Preset already selected for API: ${main_api}, name: ${name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (preset !== undefined && preset !== null) {
|
||||
console.log(`Preset found for API: ${main_api}, name: ${name}`);
|
||||
presetManager.selectPreset(preset);
|
||||
}
|
||||
}
|
||||
|
||||
function getPresetManager() {
|
||||
const apiId = main_api == 'koboldhorde' ? 'kobold' : main_api;
|
||||
|
||||
if (!Object.keys(presetManagers).includes(apiId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return presetManagers[apiId];
|
||||
}
|
||||
|
||||
function registerPresetManagers() {
|
||||
$('select[data-preset-manager-for]').each((_, e) => {
|
||||
const forData = $(e).data("preset-manager-for");
|
||||
for (const apiId of forData.split(",")) {
|
||||
console.debug(`Registering preset manager for API: ${apiId}`);
|
||||
presetManagers[apiId] = new PresetManager($(e), apiId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class PresetManager {
|
||||
constructor(select, apiId) {
|
||||
this.select = select;
|
||||
this.apiId = apiId;
|
||||
}
|
||||
|
||||
findPreset(name) {
|
||||
return $(this.select).find(`option:contains(${name})`).val();
|
||||
}
|
||||
|
||||
getSelectedPreset() {
|
||||
return $(this.select).find("option:selected").val();
|
||||
}
|
||||
|
||||
getSelectedPresetName() {
|
||||
return $(this.select).find("option:selected").text();
|
||||
}
|
||||
|
||||
selectPreset(preset) {
|
||||
$(this.select).find(`option[value=${preset}]`).prop('selected', true);
|
||||
$(this.select).val(preset).trigger("change");
|
||||
}
|
||||
|
||||
async updatePreset() {
|
||||
const selected = $(this.select).find("option:selected");
|
||||
|
||||
if (selected.val() == 'gui') {
|
||||
toastr.info('Cannot update GUI preset');
|
||||
return;
|
||||
}
|
||||
|
||||
const name = selected.text();
|
||||
await this.savePreset(name);
|
||||
toastr.success('Preset updated');
|
||||
}
|
||||
|
||||
async savePresetAs() {
|
||||
const popupText = `
|
||||
<h3>Preset name:</h3>
|
||||
<h4>Hint: Use a character/group name to bind preset to a specific chat.</h4>`;
|
||||
const name = await callPopup(popupText, "input");
|
||||
await this.savePreset(name);
|
||||
toastr.success('Preset saved');
|
||||
}
|
||||
|
||||
async savePreset(name, settings) {
|
||||
const preset = settings ?? this.getPresetSettings();
|
||||
const res = await fetch(`/save_preset`, {
|
||||
method: "POST",
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({ preset, name, apiId: this.apiId })
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
toastr.error('Failed to save preset');
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
name = data.name;
|
||||
|
||||
this.updateList(name, preset);
|
||||
}
|
||||
|
||||
getPresetList() {
|
||||
let presets = [];
|
||||
let preset_names = {};
|
||||
|
||||
switch (this.apiId) {
|
||||
case "koboldhorde":
|
||||
case "kobold":
|
||||
presets = koboldai_settings;
|
||||
preset_names = koboldai_setting_names;
|
||||
break;
|
||||
case "novel":
|
||||
presets = novelai_settings;
|
||||
preset_names = novelai_setting_names;
|
||||
break;
|
||||
case "textgenerationwebui":
|
||||
presets = textgenerationwebui_presets;
|
||||
preset_names = textgenerationwebui_preset_names;
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown API ID ${this.apiId}`);
|
||||
}
|
||||
|
||||
return { presets, preset_names };
|
||||
}
|
||||
|
||||
updateList(name, preset) {
|
||||
const { presets, preset_names } = this.getPresetList();
|
||||
const presetExists = this.apiId == "textgenerationwebui" ? preset_names.includes(name) : Object.keys(preset_names).includes(name);
|
||||
|
||||
if (presetExists) {
|
||||
if (this.apiId == "textgenerationwebui") {
|
||||
presets[preset_names.indexOf(name)] = preset;
|
||||
$(this.select).find(`option[value="${name}"]`).prop('selected', true);
|
||||
$(this.select).val(name).trigger("change");
|
||||
}
|
||||
else {
|
||||
const value = preset_names[name];
|
||||
presets[value] = preset;
|
||||
$(this.select).find(`option[value="${value}"]`).prop('selected', true);
|
||||
$(this.select).val(value).trigger("change");
|
||||
}
|
||||
}
|
||||
else {
|
||||
presets.push(preset);
|
||||
const value = presets.length - 1;
|
||||
// ooba is reversed
|
||||
if (this.apiId == "textgenerationwebui") {
|
||||
preset_names[value] = name;
|
||||
const option = $('<option></option>', { value: name, text: name, selected: true });
|
||||
$(this.select).append(option);
|
||||
$(this.select).val(name).trigger("change");
|
||||
} else {
|
||||
preset_names[name] = value;
|
||||
const option = $('<option></option>', { value: value, text: name, selected: true });
|
||||
$(this.select).append(option);
|
||||
$(this.select).val(value).trigger("change");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPresetSettings() {
|
||||
function getSettingsByApiId(apiId) {
|
||||
switch (apiId) {
|
||||
case "koboldhorde":
|
||||
case "kobold":
|
||||
return kai_settings;
|
||||
case "novel":
|
||||
return nai_settings;
|
||||
case "textgenerationwebui":
|
||||
return textgenerationwebui_settings;
|
||||
default:
|
||||
console.warn(`Unknown API ID ${apiId}`);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const filteredKeys = ['preset', 'streaming_url', 'stopping_strings', 'use_stop_sequence'];
|
||||
const settings = Object.assign({}, getSettingsByApiId(this.apiId));
|
||||
|
||||
for (const key of filteredKeys) {
|
||||
if (settings.hasOwnProperty(key)) {
|
||||
delete settings[key];
|
||||
}
|
||||
}
|
||||
|
||||
settings['genamt'] = amount_gen;
|
||||
settings['max_length'] = max_context;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
async deleteCurrentPreset() {
|
||||
const { presets, preset_names } = this.getPresetList();
|
||||
const value = this.getSelectedPreset();
|
||||
const nameToDelete = this.getSelectedPresetName();
|
||||
|
||||
if (value == 'gui') {
|
||||
toastr.info('Cannot delete GUI preset');
|
||||
return;
|
||||
}
|
||||
|
||||
$(this.select).find(`option[value="${value}"]`).remove();
|
||||
|
||||
if (this.apiId == "textgenerationwebui") {
|
||||
preset_names.splice(preset_names.indexOf(value), 1);
|
||||
} else {
|
||||
delete preset_names[nameToDelete];
|
||||
}
|
||||
|
||||
if (Object.keys(preset_names).length) {
|
||||
const nextPresetName = Object.keys(preset_names)[0];
|
||||
const newValue = preset_names[nextPresetName];
|
||||
$(this.select).find(`option[value="${newValue}"]`).attr('selected', true);
|
||||
$(this.select).trigger('change');
|
||||
}
|
||||
|
||||
const response = await fetch('/delete_preset', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({ name: nameToDelete, apiId: this.apiId }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
toastr.warning('Preset was not deleted from server');
|
||||
} else {
|
||||
toastr.success('Preset deleted');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jQuery(async () => {
|
||||
await waitUntilCondition(() => eventSource !== undefined);
|
||||
|
||||
eventSource.on(event_types.CHAT_CHANGED, autoSelectPreset);
|
||||
registerPresetManagers();
|
||||
$(document).on("click", "[data-preset-manager-update]", async function () {
|
||||
const presetManager = getPresetManager();
|
||||
|
||||
if (!presetManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
await presetManager.updatePreset();
|
||||
});
|
||||
|
||||
$(document).on("click", "[data-preset-manager-new]", async function () {
|
||||
const presetManager = getPresetManager();
|
||||
|
||||
if (!presetManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
await presetManager.savePresetAs();
|
||||
});
|
||||
|
||||
$(document).on("click", "[data-preset-manager-export]", async function () {
|
||||
const presetManager = getPresetManager();
|
||||
|
||||
if (!presetManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selected = $(presetManager.select).find("option:selected");
|
||||
const name = selected.text();
|
||||
const preset = presetManager.getPresetSettings();
|
||||
const data = JSON.stringify(preset, null, 4);
|
||||
download(data, `${name}.json`, "application/json");
|
||||
});
|
||||
|
||||
$(document).on("click", "[data-preset-manager-import]", async function () {
|
||||
$('[data-preset-manager-file]').trigger('click');
|
||||
});
|
||||
|
||||
$(document).on("change", "[data-preset-manager-file]", async function (e) {
|
||||
const presetManager = getPresetManager();
|
||||
|
||||
if (!presetManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
const file = e.target.files[0];
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
const name = file.name.replace('.json', '').replace('.settings', '');
|
||||
const data = await parseJsonFile(file);
|
||||
|
||||
await presetManager.savePreset(name, data);
|
||||
toastr.success('Preset imported');
|
||||
e.target.value = null;
|
||||
});
|
||||
|
||||
$(document).on("click", "[data-preset-manager-delete]", async function () {
|
||||
const presetManager = getPresetManager();
|
||||
|
||||
if (!presetManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
const confirm = await callPopup('Delete the preset? This action is irreversible and your current settings will be overwritten.', 'confirm');
|
||||
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
await presetManager.deleteCurrentPreset();
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
})
|
|
@ -192,7 +192,7 @@ function goToCharacterCallback(_, name) {
|
|||
const characterIndex = findCharacterIndex(name);
|
||||
|
||||
if (characterIndex !== -1) {
|
||||
openChat(characterIndex);
|
||||
openChat(new String(characterIndex));
|
||||
} else {
|
||||
console.warn(`No matches found for name "${name}"`);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
getStoppingStrings,
|
||||
max_context,
|
||||
saveSettingsDebounced,
|
||||
setGenerationParamsFromPreset,
|
||||
} from "../script.js";
|
||||
|
||||
export {
|
||||
|
@ -11,7 +12,7 @@ export {
|
|||
generateTextGenWithStreaming,
|
||||
}
|
||||
|
||||
let textgenerationwebui_settings = {
|
||||
const textgenerationwebui_settings = {
|
||||
temp: 0.7,
|
||||
top_p: 0.5,
|
||||
top_k: 40,
|
||||
|
@ -44,8 +45,8 @@ let textgenerationwebui_settings = {
|
|||
mirostat_eta: 0.1,
|
||||
};
|
||||
|
||||
let textgenerationwebui_presets = [];
|
||||
let textgenerationwebui_preset_names = [];
|
||||
export let textgenerationwebui_presets = [];
|
||||
export let textgenerationwebui_preset_names = [];
|
||||
|
||||
const setting_names = [
|
||||
"temp",
|
||||
|
@ -89,6 +90,7 @@ function selectPreset(name) {
|
|||
const value = preset[name];
|
||||
setSettingByName(name, value, true);
|
||||
}
|
||||
setGenerationParamsFromPreset(preset);
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
|
|
|
@ -4500,14 +4500,14 @@ toolcool-color-picker {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.openai_preset_buttons {
|
||||
.openai_preset_buttons, .preset_buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.openai_preset_buttons select {
|
||||
.openai_preset_buttons select, .preset_buttons select {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
@ -5422,4 +5422,4 @@ body.waifuMode .zoomed_avatar {
|
|||
background-color: var(--SmartThemeBlurTintColor);
|
||||
text-align: center;
|
||||
line-height: 14px;
|
||||
}
|
||||
}
|
||||
|
|
57
server.js
57
server.js
|
@ -1108,7 +1108,7 @@ app.post("/editcharacterattribute", jsonParser, async function (request, respons
|
|||
}
|
||||
});
|
||||
|
||||
app.post("/deletecharacter", urlencodedParser, async function (request, response) {
|
||||
app.post("/deletecharacter", jsonParser, async function (request, response) {
|
||||
if (!request.body || !request.body.avatar_url) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
@ -3341,6 +3341,47 @@ app.post("/tokenize_openai", jsonParser, function (request, response_tokenize_op
|
|||
response_tokenize_openai.send({ "token_count": num_tokens });
|
||||
});
|
||||
|
||||
app.post("/save_preset", jsonParser, function (request, response) {
|
||||
const name = sanitize(request.body.name);
|
||||
if (!request.body.preset || !name) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const filename = `${name}.settings`;
|
||||
const directory = getPresetFolderByApiId(request.body.apiId);
|
||||
|
||||
if (!directory) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const fullpath = path.join(directory, filename);
|
||||
fs.writeFileSync(fullpath, JSON.stringify(request.body.preset, null, 4), 'utf-8');
|
||||
return response.send({ name });
|
||||
});
|
||||
|
||||
app.post("/delete_preset", jsonParser, function (request, response) {
|
||||
const name = sanitize(request.body.name);
|
||||
if (!name) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const filename = `${name}.settings`;
|
||||
const directory = getPresetFolderByApiId(request.body.apiId);
|
||||
|
||||
if (!directory) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const fullpath = path.join(directory, filename);
|
||||
|
||||
if (fs.existsSync) {
|
||||
fs.unlinkSync(fullpath);
|
||||
return response.sendStatus(200);
|
||||
} else {
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/savepreset_openai", jsonParser, function (request, response) {
|
||||
const name = sanitize(request.query.name);
|
||||
if (!request.body || !name) {
|
||||
|
@ -3353,6 +3394,20 @@ app.post("/savepreset_openai", jsonParser, function (request, response) {
|
|||
return response.send({ name });
|
||||
});
|
||||
|
||||
function getPresetFolderByApiId(apiId) {
|
||||
switch (apiId) {
|
||||
case 'kobold':
|
||||
case 'koboldhorde':
|
||||
return directories.koboldAI_Settings;
|
||||
case 'novel':
|
||||
return directories.novelAI_Settings;
|
||||
case 'textgenerationwebui':
|
||||
return directories.textGen_Settings;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function createTokenizationHandler(getTokenizerFn) {
|
||||
return async function (request, response) {
|
||||
if (!request.body) {
|
||||
|
|
Loading…
Reference in New Issue