mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge branch 'dev' into pkg
This commit is contained in:
16
package-lock.json
generated
16
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "sillytavern",
|
"name": "sillytavern",
|
||||||
"version": "1.5.3",
|
"version": "1.5.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "sillytavern",
|
"name": "sillytavern",
|
||||||
"version": "1.5.3",
|
"version": "1.5.4",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dqbd/tiktoken": "^1.0.2",
|
"@dqbd/tiktoken": "^1.0.2",
|
||||||
@ -20,6 +20,7 @@
|
|||||||
"exifreader": "^4.12.0",
|
"exifreader": "^4.12.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"gpt3-tokenizer": "^1.1.5",
|
"gpt3-tokenizer": "^1.1.5",
|
||||||
|
"ip-matching": "^2.1.2",
|
||||||
"ipaddr.js": "^2.0.1",
|
"ipaddr.js": "^2.0.1",
|
||||||
"jimp": "^0.22.7",
|
"jimp": "^0.22.7",
|
||||||
"jquery": "^3.6.4",
|
"jquery": "^3.6.4",
|
||||||
@ -34,6 +35,7 @@
|
|||||||
"png-chunks-extract": "^1.0.0",
|
"png-chunks-extract": "^1.0.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"sanitize-filename": "^1.6.3",
|
"sanitize-filename": "^1.6.3",
|
||||||
|
"uniqolor": "^1.1.0",
|
||||||
"webp-converter": "2.3.2",
|
"webp-converter": "2.3.2",
|
||||||
"ws": "^8.13.0",
|
"ws": "^8.13.0",
|
||||||
"yargs": "^17.7.1"
|
"yargs": "^17.7.1"
|
||||||
@ -1657,6 +1659,11 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ip-matching": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ip-matching/-/ip-matching-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-/ok+VhKMasgR5gvTRViwRFQfc0qYt9Vdowg6TO4/pFlDCob5ZjGPkwuOoQVCd5OrMm20zqh+1vA8KLJZTeWudg=="
|
||||||
|
},
|
||||||
"node_modules/ipaddr.js": {
|
"node_modules/ipaddr.js": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -3084,6 +3091,11 @@
|
|||||||
"version": "0.0.6",
|
"version": "0.0.6",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/uniqolor": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uniqolor/-/uniqolor-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-j2XyokF24fsj+L5u6fbu4rM3RQc6VWJuAngYM2k0ZdG3yiVxt0smLkps2GmQIYqK8VkELGdM9vFU/HfOkK/zoQ=="
|
||||||
|
},
|
||||||
"node_modules/universalify": {
|
"node_modules/universalify": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"exifreader": "^4.12.0",
|
"exifreader": "^4.12.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"gpt3-tokenizer": "^1.1.5",
|
"gpt3-tokenizer": "^1.1.5",
|
||||||
|
"ip-matching": "^2.1.2",
|
||||||
"ipaddr.js": "^2.0.1",
|
"ipaddr.js": "^2.0.1",
|
||||||
"jimp": "^0.22.7",
|
"jimp": "^0.22.7",
|
||||||
"jquery": "^3.6.4",
|
"jquery": "^3.6.4",
|
||||||
@ -25,6 +26,7 @@
|
|||||||
"png-chunks-extract": "^1.0.0",
|
"png-chunks-extract": "^1.0.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"sanitize-filename": "^1.6.3",
|
"sanitize-filename": "^1.6.3",
|
||||||
|
"uniqolor": "^1.1.0",
|
||||||
"webp-converter": "2.3.2",
|
"webp-converter": "2.3.2",
|
||||||
"ws": "^8.13.0",
|
"ws": "^8.13.0",
|
||||||
"yargs": "^17.7.1"
|
"yargs": "^17.7.1"
|
||||||
@ -40,7 +42,7 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Cohee1207/SillyTavern.git"
|
"url": "https://github.com/Cohee1207/SillyTavern.git"
|
||||||
},
|
},
|
||||||
"version": "1.5.3",
|
"version": "1.5.4",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node server.js",
|
"start": "node server.js",
|
||||||
"pkg": "pkg ."
|
"pkg": "pkg ."
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
<script src="scripts/moment.min.js"></script>
|
<script src="scripts/moment.min.js"></script>
|
||||||
<script src="scripts/cropper.min.js"></script>
|
<script src="scripts/cropper.min.js"></script>
|
||||||
<script src="scripts/jquery-cropper.min.js"></script>
|
<script src="scripts/jquery-cropper.min.js"></script>
|
||||||
|
<script type="module" src="scripts/eventemitter.js"></script>
|
||||||
<script type="module" src="scripts/power-user.js"></script>
|
<script type="module" src="scripts/power-user.js"></script>
|
||||||
<script type="module" src="scripts/swiped-events.js"></script>
|
<script type="module" src="scripts/swiped-events.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="style.css">
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
@ -366,6 +367,15 @@
|
|||||||
<input id="openai_reverse_proxy" type="text" class="text_pole" placeholder="https://api.openai.com/v1" maxlength="100" />
|
<input id="openai_reverse_proxy" type="text" class="text_pole" placeholder="https://api.openai.com/v1" maxlength="100" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="range-block">
|
||||||
|
<label for="oai_breakdown" class="checkbox_label widthFreeExpand">
|
||||||
|
<input id="oai_breakdown" type="checkbox" />
|
||||||
|
Token Breakdown
|
||||||
|
</label>
|
||||||
|
<div class="toggle-description justifyLeft">
|
||||||
|
Display a breakdown of the tokens used in the request.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="range-block">
|
<div class="range-block">
|
||||||
<div class="range-block-title">
|
<div class="range-block-title">
|
||||||
Context Size (tokens)
|
Context Size (tokens)
|
||||||
@ -738,7 +748,7 @@
|
|||||||
<div class="range-block-title">
|
<div class="range-block-title">
|
||||||
Seed
|
Seed
|
||||||
</div>
|
</div>
|
||||||
<input type="number" id="seed_textgenerationwebui" class="text_pole" maxlength="100" />
|
<input type="number" id="seed_textgenerationwebui" class="text_pole wide100p" maxlength="100" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="openai_settings">
|
<div id="openai_settings">
|
||||||
@ -961,7 +971,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="rm_api_block" class="drawer-content closedDrawer">
|
<div id="rm_api_block" class="drawer-content closedDrawer">
|
||||||
<h3 id="title_api">API</h3>
|
<h3 id="title_api">API</h3>
|
||||||
<div class="flex-container">
|
<div class="flex-container flexFlowColumn">
|
||||||
<div id="main-API-selector-block">
|
<div id="main-API-selector-block">
|
||||||
<select id="main_api">
|
<select id="main_api">
|
||||||
<option value="kobold">KoboldAI</option>
|
<option value="kobold">KoboldAI</option>
|
||||||
@ -1043,7 +1053,7 @@
|
|||||||
</ol>
|
</ol>
|
||||||
</span>
|
</span>
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<input id="api_key_novel" name="api_key_novel" class="text_pole flex1" maxlength="500" size="35" type="text">
|
<input id="api_key_novel" name="api_key_novel" class="text_pole flex1 wide100p" maxlength="500" size="35" type="text">
|
||||||
<div title="Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_novel"></div>
|
<div title="Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_novel"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="neutral_warning">For privacy reasons, your API key will be hidden after you reload the page.</div>
|
<div class="neutral_warning">For privacy reasons, your API key will be hidden after you reload the page.</div>
|
||||||
@ -1065,24 +1075,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="textgenerationwebui_api" style="display: none;position: relative;">
|
<div id="textgenerationwebui_api" style="display: none;position: relative;">
|
||||||
<div class="oobabooga_logo">
|
<div class="oobabooga_logo flex-container">
|
||||||
<a href="https://github.com/oobabooga/text-generation-webui" target="_blank">
|
<a href="https://github.com/oobabooga/text-generation-webui" target="_blank">
|
||||||
oobabooga/text-generation-webui
|
oobabooga/text-generation-webui
|
||||||
</a>
|
</a>
|
||||||
|
<span>
|
||||||
|
Make sure you run it with <tt>--api</tt> flag
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<div>
|
||||||
Make sure you run it with <tt>--api</tt> flag
|
<div class="flex-container">
|
||||||
</span>
|
<div class="flex1">
|
||||||
<form action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
<h4>Blocking API url</h4>
|
||||||
<h4>Blocking API url</h4>
|
<h5>Example: http://127.0.0.1:5000/</h5>
|
||||||
<h5>Example: http://127.0.0.1:5000/</h5>
|
<input id="textgenerationwebui_api_url_text" name="textgenerationwebui_api_url" class="text_pole wide100p"
|
||||||
<input id="textgenerationwebui_api_url_text" name="textgenerationwebui_api_url" class="text_pole" maxlength="500" value="" autocomplete="off">
|
maxlength="500" value="">
|
||||||
|
</div>
|
||||||
|
<div class="flex1">
|
||||||
|
<h4>Streaming API url</h4>
|
||||||
|
<h5>Example: ws://127.0.0.1:5005/api/v1/stream</h5>
|
||||||
|
<input id="streaming_url_textgenerationwebui" type="text" class="text_pole wide100p" maxlength="500" value="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<input id="api_button_textgenerationwebui" class="menu_button" type="submit" value="Connect">
|
<input id="api_button_textgenerationwebui" class="menu_button" type="submit" value="Connect">
|
||||||
<h4>Streaming API url</h4>
|
|
||||||
<h5>Example: ws://127.0.0.1:5005/api/v1/stream</h5>
|
|
||||||
<input id="streaming_url_textgenerationwebui" type="text" class="text_pole" maxlength="500" value="" autocomplete="off">
|
|
||||||
<div id="api_loading_textgenerationwebui" class="api-load-icon fa-solid fa-hourglass fa-spin"></div>
|
<div id="api_loading_textgenerationwebui" class="api-load-icon fa-solid fa-hourglass fa-spin"></div>
|
||||||
</form>
|
</div>
|
||||||
<div class="online_status4">
|
<div class="online_status4">
|
||||||
<div class="online_status_indicator4"></div>
|
<div class="online_status_indicator4"></div>
|
||||||
<div class="online_status_text4">Not connected</div>
|
<div class="online_status_text4">Not connected</div>
|
||||||
@ -1176,7 +1193,7 @@
|
|||||||
|
|
||||||
<div id="advanced-formatting-button" class="drawer">
|
<div id="advanced-formatting-button" class="drawer">
|
||||||
<div class="drawer-toggle">
|
<div class="drawer-toggle">
|
||||||
<div class="drawer-icon fa-solid fa-font closedIcon" title="AI Reponse Formatting"></div>
|
<div class="drawer-icon fa-solid fa-font closedIcon" title="AI Response Formatting"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="drawer-content">
|
<div class="drawer-content">
|
||||||
<h3>Advanced Formatting
|
<h3>Advanced Formatting
|
||||||
@ -1207,6 +1224,15 @@
|
|||||||
<input id="disable-start-formatting-checkbox" type="checkbox" />
|
<input id="disable-start-formatting-checkbox" type="checkbox" />
|
||||||
Disable chat start formatting
|
Disable chat start formatting
|
||||||
</label>
|
</label>
|
||||||
|
<label class="checkbox_label" for="trim_sentences_checkbox">
|
||||||
|
<input id="trim_sentences_checkbox" type="checkbox" />
|
||||||
|
Trim Incomplete Sentences
|
||||||
|
</label>
|
||||||
|
<!-- Add margin since this is a child of above -->
|
||||||
|
<label style="margin-left: 1em;" class="checkbox_label" for="include_newline_checkbox">
|
||||||
|
<input id="include_newline_checkbox" type="checkbox" />
|
||||||
|
Include Newline
|
||||||
|
</label>
|
||||||
<div>
|
<div>
|
||||||
<h4>
|
<h4>
|
||||||
Custom Chat Separator
|
Custom Chat Separator
|
||||||
@ -1247,7 +1273,7 @@
|
|||||||
Input Sequence
|
Input Sequence
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div>
|
||||||
<input id="instruct_input_sequence" class="text_pole textarea_compact" type="text" maxlength="100" />
|
<input id="instruct_input_sequence" class="text_pole wide100p textarea_compact" type="text" maxlength="100" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex1">
|
<div class="flex1">
|
||||||
@ -1255,7 +1281,7 @@
|
|||||||
Output Sequence
|
Output Sequence
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div>
|
||||||
<input id="instruct_output_sequence" class="text_pole textarea_compact" type="text" maxlength="100" />
|
<input id="instruct_output_sequence" class="text_pole wide100p textarea_compact" type="text" maxlength="100" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1265,7 +1291,7 @@
|
|||||||
System Sequence
|
System Sequence
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div>
|
||||||
<input id="instruct_system_sequence" class="text_pole textarea_compact" type="text" maxlength="100" />
|
<input id="instruct_system_sequence" class="text_pole wide100p textarea_compact" type="text" maxlength="100" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex1">
|
<div class="flex1">
|
||||||
@ -1273,7 +1299,7 @@
|
|||||||
Stop Sequence
|
Stop Sequence
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div>
|
||||||
<input id="instruct_stop_sequence" class="text_pole textarea_compact" type="text" maxlength="100" />
|
<input id="instruct_stop_sequence" class="text_pole wide100p textarea_compact" type="text" maxlength="100" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1346,24 +1372,22 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="anchors-block">
|
<div id="context-templates-block" style="display:none">
|
||||||
<h4>
|
<h4>
|
||||||
Anchors Order
|
Context Templates
|
||||||
<a href="/notes#anchors" class="notes-link" target="_blank">
|
|
||||||
<span class="note-link-span">?</span>
|
|
||||||
</a>
|
|
||||||
</h4>
|
</h4>
|
||||||
<select id="anchor_order">
|
<div>
|
||||||
<option value="0">Character then Style</option>
|
<label>Presets:</label>
|
||||||
<option value="1">Style then Character</option>
|
<div class="flex-container flexGap5">
|
||||||
</select>
|
<select id="prompt_template" class="flex1 margin0">
|
||||||
<div id="anchor_checkbox">
|
<option value="None">None</option>
|
||||||
<label for="character_anchor"><input id="character_anchor" type="checkbox" />
|
<option value="Classic">Classic</option>
|
||||||
Character Anchor
|
<option value="Pygmalion">Pygmalion</option>
|
||||||
</label>
|
</select>
|
||||||
<label for="style_anchor"><input id="style_anchor" type="checkbox" />
|
<div id="context_template_edit" class="menu_button fa-solid fa-pencil margin0" title="Edit"></div>
|
||||||
Style Anchor
|
<div id="context_template_new" class="menu_button fa-solid fa-plus margin0" title="Add new"></div>
|
||||||
</label>
|
<div id="context_template_delete" class="menu_button fa-solid fa-trash-can margin0" title="Delete"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1373,12 +1397,20 @@
|
|||||||
|
|
||||||
<div id="WI-SP-button" class="drawer">
|
<div id="WI-SP-button" class="drawer">
|
||||||
<div class="drawer-toggle drawer-header">
|
<div class="drawer-toggle drawer-header">
|
||||||
<div class="drawer-icon fa-solid fa-book-atlas closedIcon " title="World Info & Soft Prompts"></div>
|
<div id="WIDrawerIcon" class="drawer-icon fa-solid fa-book-atlas closedIcon " title="World Info & Soft Prompts"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="drawer-content closedDrawer">
|
<div id="WorldInfo" class="drawer-content closedDrawer">
|
||||||
|
<div id="WorldInfoheader" class="fa-solid fa-grip drag-grabber"></div>
|
||||||
|
<div id="WI_panel_pin_div" title="Locked = World Editor will stay open">
|
||||||
|
<input type="checkbox" id="WI_panel_pin">
|
||||||
|
<label for="WI_panel_pin">
|
||||||
|
<div class="unchecked fa-solid fa-lock-open "></div>
|
||||||
|
<div class="checked fa-solid fa-lock "></div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<div id="wi-holder">
|
<div id="wi-holder">
|
||||||
<h3>
|
<h3>
|
||||||
World Info
|
World Selector
|
||||||
<a href="/notes#worldinfo" class="notes-link" target="_blank">
|
<a href="/notes#worldinfo" class="notes-link" target="_blank">
|
||||||
<span class="note-link-span">?</span>
|
<span class="note-link-span">?</span>
|
||||||
</a>
|
</a>
|
||||||
@ -1440,6 +1472,41 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="world_popup">
|
||||||
|
<hr>
|
||||||
|
<div id="world_popup_text">
|
||||||
|
<!-- <div id="world_cross" class="fa-solid fa-circle-xmark"></div> -->
|
||||||
|
<div id="world_popup_header" class="flex-container flexGap5">
|
||||||
|
<!-- Consider changing logo to something else -->
|
||||||
|
<div class="world_popup_logo_block">
|
||||||
|
<!-- <img src="img/book2.png" id="world_logo"> -->
|
||||||
|
<h3>
|
||||||
|
World Info Editor
|
||||||
|
<a href="/notes#worldinfoentry" class="notes-link" target="_blank"><span class="note-link-span">?</span></a>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div id="OpenAllWIEntries" class="menu_button fa-solid fa-expand"></div>
|
||||||
|
<div id="CloseAllWIEntries" class="menu_button fa-solid fa-compress"></div>
|
||||||
|
<!-- <div class="world_popup_expander"> </div> -->
|
||||||
|
<form id="form_rename_world" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||||
|
<input id="world_popup_name" name="world_popup_name" class="text_pole" maxlength="99" size="32" value="" autocomplete="off">
|
||||||
|
<input id="world_popup_name_button" class="menu_button" type="submit" value="Rename">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="world_popup_entries_list">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="world_popup_bottom_holder">
|
||||||
|
<div id="world_popup_new" class="menu_button">New Entry</div>
|
||||||
|
<!-- <span class="world_popup_expander"> </span> -->
|
||||||
|
<div id="world_popup_export" class="menu_button">Export</div>
|
||||||
|
<div id="world_popup_delete" class="menu_button">Delete World</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="softprompt_block">
|
<div id="softprompt_block">
|
||||||
<h4>Soft Prompt</h4>
|
<h4>Soft Prompt</h4>
|
||||||
@ -1663,6 +1730,10 @@
|
|||||||
<input id="auto_scroll_chat_to_bottom" type="checkbox" />
|
<input id="auto_scroll_chat_to_bottom" type="checkbox" />
|
||||||
Auto-scroll Chat
|
Auto-scroll Chat
|
||||||
</label>
|
</label>
|
||||||
|
<label for="console_log_prompts">
|
||||||
|
<input id="console_log_prompts" type="checkbox" />
|
||||||
|
Log prompts to console
|
||||||
|
</label>
|
||||||
<label for="render_formulas">
|
<label for="render_formulas">
|
||||||
<input id="render_formulas" type="checkbox" />
|
<input id="render_formulas" type="checkbox" />
|
||||||
Render Formulas
|
Render Formulas
|
||||||
@ -1670,6 +1741,14 @@
|
|||||||
<span class="note-link-span">?</span>
|
<span class="note-link-span">?</span>
|
||||||
</a>
|
</a>
|
||||||
</label>
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div name="NameAndAvatar" class="flex-container flexFlowColumn drawer25pWidth">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="inline-drawer wide100p flexFlowColumn">
|
||||||
|
|
||||||
<div class="flex-container flexFlowColumn">
|
<div class="flex-container flexFlowColumn">
|
||||||
<h4>
|
<h4>
|
||||||
Send on Enter
|
Send on Enter
|
||||||
@ -1680,14 +1759,32 @@
|
|||||||
<option value="1">Always enabled</option>
|
<option value="1">Always enabled</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div name="NameAndAvatar" class="flex-container flexFlowColumn drawer25pWidth">
|
<div id="groupCurrentMemberListToggle" class="inline-drawer-toggle inline-drawer-header">
|
||||||
|
<b>Auto-swipe</b>
|
||||||
|
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
||||||
|
</div>
|
||||||
|
<div class="inline-drawer-content">
|
||||||
|
|
||||||
|
<label class="checkbox_label" for="auto_swipe">
|
||||||
|
<input id="auto_swipe" type="checkbox" />
|
||||||
|
Enabled
|
||||||
|
</label>
|
||||||
|
<div>Minimum generated message length</div>
|
||||||
|
<input id="auto_swipe_minimum_length" name="auto_swipe_minimum_length" type="number" min="0" step="1" value="0" class="text_pole">
|
||||||
|
<div>Blacklisted words</div>
|
||||||
|
<div class="auto_swipe">
|
||||||
|
<input id="auto_swipe_blacklist" name="auto_swipe_blacklist" placeholder="words you dont want generated separated by comma ','" class="text_pole" maxlength="500" value="" autocomplete="off">
|
||||||
|
<div>Blacklisted word count to swipe</div>
|
||||||
|
<input id="auto_swipe_blacklist_threshold" name="auto_swipe_blacklist_threshold" type="number" min="0" step="1" value="1" class="text_pole">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div name="NameChanger">
|
<div name="NameChanger">
|
||||||
<h4>Name</h4>
|
<h4>Name</h4>
|
||||||
<div class="change_name">
|
<div class="change_name">
|
||||||
<input id="your_name" name="your_name" placeholder="Enter your name" class="text_pole" maxlength="50" value="" autocomplete="off">
|
<input id="your_name" name="your_name" placeholder="Enter your name" class="text_pole wide100p" maxlength="50" value="" autocomplete="off">
|
||||||
<div id="your_name_button" class="menu_button fa-solid fa-check" title="Click to set a new User Name">
|
<div id="your_name_button" class="menu_button fa-solid fa-check" title="Click to set a new User Name">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1822,7 +1919,7 @@
|
|||||||
|
|
||||||
<div id="tags_div">
|
<div id="tags_div">
|
||||||
<div class="tag_controls">
|
<div class="tag_controls">
|
||||||
<input id="tagInput" class="text_pole tag_input" placeholder="Search / Create tags" maxlength="25" />
|
<input id="tagInput" class="text_pole tag_input wide100p margin0" placeholder="Search / Create tags" maxlength="25" />
|
||||||
<div class="tags_view menu_button fa-solid fa-tags" title="View all tags"></div>
|
<div class="tags_view menu_button fa-solid fa-tags" title="View all tags"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="tagList" class="tags"></div>
|
<div id="tagList" class="tags"></div>
|
||||||
@ -1875,15 +1972,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="inline-drawer-content">
|
<div class="inline-drawer-content">
|
||||||
<div name="group-metadata-controls" class="marginTopBot5">
|
<div name="group-metadata-controls" class="marginTopBot5">
|
||||||
<input id="rm_group_chat_name" class="text_pole" type="text" name="chat_name" placeholder="Chat Name (Optional)" maxlength="100" />
|
<input id="rm_group_chat_name" class="text_pole wide100p" type="text" name="chat_name" placeholder="Chat Name (Optional)" maxlength="100" />
|
||||||
<div id="group_tags_div" class="wide100p">
|
<div id="group_tags_div" class="wide100p">
|
||||||
<div class="tag_controls">
|
<div class="tag_controls">
|
||||||
<input id="groupTagInput" class="text_pole tag_input flex1" placeholder="Search / Create tags" maxlength="25" />
|
<input id="groupTagInput" class="text_pole tag_input flex1 margin0" placeholder="Search / Create tags" maxlength="25" />
|
||||||
<div class="tags_view menu_button fa-solid fa-tags" title="View all tags"></div>
|
<div class="tags_view menu_button fa-solid fa-tags margin0" title="View all tags"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="groupTagList" class="tags paddingTopBot5"></div>
|
<div id="groupTagList" class="tags paddingTopBot5"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="rm_group_top_bar" class="flex-container spaceEvenly width100p">
|
<div id="rm_group_top_bar" class="flex-container spaceBetween width100p">
|
||||||
<div name="GroupStragegyAndOrder" id="rm_group_buttons" class="fontsize80p flex-container paddingLeftRight5">
|
<div name="GroupStragegyAndOrder" id="rm_group_buttons" class="fontsize80p flex-container paddingLeftRight5">
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="flex-container flexnowrap width100p whitespacenowrap">
|
<div class="flex-container flexnowrap width100p whitespacenowrap">
|
||||||
@ -1925,21 +2022,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="inline-drawer wide100p flexFlowColumn">
|
|
||||||
<div id="groupAddMemberListToggle" class="inline-drawer-toggle inline-drawer-header">
|
|
||||||
Add Members
|
|
||||||
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
|
||||||
</div>
|
|
||||||
<div class="inline-drawer-content">
|
|
||||||
<div name="Unadded Char List" class="flex-container flexFlowColumn overflowYAuto flex1">
|
|
||||||
<div id="rm_group_add_members_header">
|
|
||||||
<input id="rm_group_filter" class="text_pole" type="search" placeholder="Filter..." maxlength="100" />
|
|
||||||
<div id="group_fav_filter" class="menu_button fa-solid fa-ranking-star" title="Show only favorites"></div>
|
|
||||||
</div>
|
|
||||||
<div id="rm_group_add_members" class="overflowYAuto flex-container"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="inline-drawer wide100p flexFlowColumn">
|
<div class="inline-drawer wide100p flexFlowColumn">
|
||||||
<div id="groupCurrentMemberListToggle" class="inline-drawer-toggle inline-drawer-header">
|
<div id="groupCurrentMemberListToggle" class="inline-drawer-toggle inline-drawer-header">
|
||||||
Current Members
|
Current Members
|
||||||
@ -1951,6 +2033,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="inline-drawer wide100p flexFlowColumn">
|
||||||
|
<div id="groupAddMemberListToggle" class="inline-drawer-toggle inline-drawer-header">
|
||||||
|
Add Members
|
||||||
|
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
||||||
|
</div>
|
||||||
|
<div class="inline-drawer-content">
|
||||||
|
<div name="Unadded Char List" class="flex-container flexFlowColumn overflowYAuto flex1">
|
||||||
|
<div id="rm_group_add_members_header">
|
||||||
|
<input id="rm_group_filter" class="text_pole margin0" type="search" placeholder="Filter..." maxlength="100" />
|
||||||
|
<div id="group_fav_filter" class="menu_button fa-solid fa-ranking-star margin0" title="Show only favorites"></div>
|
||||||
|
</div>
|
||||||
|
<div id="rm_group_add_members" class="overflowYAuto flex-container"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -1967,7 +2064,7 @@
|
|||||||
<div id="rm_button_create" title="Create New Character" class="menu_button fa-solid fa-user-plus "></div>
|
<div id="rm_button_create" title="Create New Character" class="menu_button fa-solid fa-user-plus "></div>
|
||||||
<div id="character_import_button" title="Import Character from File" class="menu_button fa-solid fa-file-arrow-up "></div>
|
<div id="character_import_button" title="Import Character from File" class="menu_button fa-solid fa-file-arrow-up "></div>
|
||||||
<div id="rm_button_group_chats" title="Create New Chat Group" class="menu_button fa-solid fa-users-gear "></div>
|
<div id="rm_button_group_chats" title="Create New Chat Group" class="menu_button fa-solid fa-users-gear "></div>
|
||||||
<input id="character_search_bar" class="text_pole" type="search" placeholder="Search..." maxlength="50" />
|
<input id="character_search_bar" class="text_pole width100p" type="search" placeholder="Search..." maxlength="50" />
|
||||||
<select id="character_sort_order" title="Characters sorting order">
|
<select id="character_sort_order" title="Characters sorting order">
|
||||||
<option data-field="name" data-order="asc">A-Z</option>
|
<option data-field="name" data-order="asc">A-Z</option>
|
||||||
<option data-field="name" data-order="desc">Z-A</option>
|
<option data-field="name" data-order="desc">Z-A</option>
|
||||||
@ -2022,7 +2119,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 id="character_popup_text_h3"></h3> - Advanced Defininitions
|
<h3 id="character_popup_text_h3"></h3> - Advanced Definitions
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -2047,7 +2144,7 @@
|
|||||||
|
|
||||||
<div id="talkativeness_div">
|
<div id="talkativeness_div">
|
||||||
<h4>Talkativeness</h4>
|
<h4>Talkativeness</h4>
|
||||||
<h5>How often the chracter speaks in <span class="warning">group chats!</span>
|
<h5>How often the character speaks in <span class="warning">group chats!</span>
|
||||||
</h5>
|
</h5>
|
||||||
<input id="talkativeness_slider" name="talkativeness" type="range" min="0" max="1" step="0.05" value="0.5" form="form_create">
|
<input id="talkativeness_slider" name="talkativeness" type="range" min="0" max="1" step="0.05" value="0.5" form="form_create">
|
||||||
<div id="talkativeness_hint">
|
<div id="talkativeness_hint">
|
||||||
@ -2067,38 +2164,7 @@
|
|||||||
<div id="character_popup_ok" class="menu_button">Save</div>
|
<div id="character_popup_ok" class="menu_button">Save</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="world_popup">
|
|
||||||
<div id="world_popup_text">
|
|
||||||
<div id="world_cross" class="fa-solid fa-circle-xmark"></div>
|
|
||||||
<div id="world_popup_header">
|
|
||||||
<!-- Consider changing logo to something else -->
|
|
||||||
<div class="world_popup_logo_block">
|
|
||||||
<img src="img/book2.png" id="world_logo">
|
|
||||||
<h3>
|
|
||||||
World Info Editor
|
|
||||||
<a href="/notes#worldinfoentry" class="notes-link" target="_blank"><span class="note-link-span">?</span></a>
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div id="OpenAllWIEntries" class="menu_button fa-solid fa-expand"></div>
|
|
||||||
<div id="CloseAllWIEntries" class="menu_button fa-solid fa-compress"></div>
|
|
||||||
<div class="world_popup_expander"> </div>
|
|
||||||
<form id="form_rename_world" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
|
||||||
<input id="world_popup_name" name="world_popup_name" class="text_pole" maxlength="99" size="32" value="" autocomplete="off">
|
|
||||||
<input id="world_popup_name_button" class="menu_button" type="submit" value="Rename">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="world_popup_entries_list">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="world_popup_bottom_holder">
|
|
||||||
<div id="world_popup_new" class="menu_button">New Entry</div>
|
|
||||||
<span class="world_popup_expander"> </span>
|
|
||||||
<div id="world_popup_export" class="menu_button">Export</div>
|
|
||||||
<div id="world_popup_delete" class="menu_button">Delete World</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="shadow_select_chat_popup">
|
<div id="shadow_select_chat_popup">
|
||||||
<div id="select_chat_popup">
|
<div id="select_chat_popup">
|
||||||
<div id="select_chat_import"> <!-- import chat popup header -->
|
<div id="select_chat_import"> <!-- import chat popup header -->
|
||||||
@ -2177,6 +2243,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div id="entry_edit_template" class="template_element">
|
<div id="entry_edit_template" class="template_element">
|
||||||
<div class="world_entry">
|
<div class="world_entry">
|
||||||
<form class="world_entry_form">
|
<form class="world_entry_form">
|
||||||
@ -2186,14 +2253,14 @@
|
|||||||
<div class="world_entry_form_control">
|
<div class="world_entry_form_control">
|
||||||
<label for="key">
|
<label for="key">
|
||||||
<h4>Keywords</h4>
|
<h4>Keywords</h4>
|
||||||
<h5>Separate with commas</h5>
|
<h5>Split by commas</h5>
|
||||||
</label>
|
</label>
|
||||||
<textarea class="text_pole keyprimarytextpole" name="key" rows="1" placeholder="" maxlength="250"></textarea>
|
<textarea class="text_pole keyprimarytextpole" name="key" rows="1" placeholder="" maxlength="250"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="world_entry_form_control keysecondary">
|
<div class="world_entry_form_control keysecondary">
|
||||||
<label for="keysecondary">
|
<label for="keysecondary">
|
||||||
<h4>Secondary Required Keywords</h4>
|
<h4>2nd Keywords</h4>
|
||||||
<h5>Separate with commas</h5>
|
<h5>Split by commas</h5>
|
||||||
</label>
|
</label>
|
||||||
<textarea class="text_pole keysecondarytextpole" name="keysecondary" rows="1" placeholder="(secondary keywords here)" maxlength="250"></textarea>
|
<textarea class="text_pole keysecondarytextpole" name="keysecondary" rows="1" placeholder="(secondary keywords here)" maxlength="250"></textarea>
|
||||||
</div>
|
</div>
|
||||||
@ -2327,6 +2394,8 @@
|
|||||||
<span class="name_text">${characterName}</span>
|
<span class="name_text">${characterName}</span>
|
||||||
|
|
||||||
<div class="mes_buttons">
|
<div class="mes_buttons">
|
||||||
|
<div title="Narrate" class="mes_narrate fa-solid fa-bullhorn"></div>
|
||||||
|
<div title="Prompt" class="mes_prompt fa-solid fa-square-poll-horizontal "></div>
|
||||||
<div title="Copy" class="mes_copy fa-solid fa-copy "></div>
|
<div title="Copy" class="mes_copy fa-solid fa-copy "></div>
|
||||||
<div title="Edit" class="mes_edit fa-solid fa-pencil "></div>
|
<div title="Edit" class="mes_edit fa-solid fa-pencil "></div>
|
||||||
</div>
|
</div>
|
||||||
@ -2415,12 +2484,18 @@
|
|||||||
<div id="typing_indicator_template" class="template_element">
|
<div id="typing_indicator_template" class="template_element">
|
||||||
<div class="typing_indicator"><span class="typing_indicator_name">CHAR</span> is typing</div>
|
<div class="typing_indicator"><span class="typing_indicator_name">CHAR</span> is typing</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="movingDivs"></div>
|
||||||
<div id="sheld">
|
<div id="sheld">
|
||||||
<div id="sheldheader" class="fa-solid fa-grip drag-grabber"></div>
|
<div id="sheldheader" class="fa-solid fa-grip drag-grabber"></div>
|
||||||
<!-- <div class="pull-tab"></div> -->
|
<!-- <div class="pull-tab"></div> -->
|
||||||
<div id="chat">
|
<div id="chat">
|
||||||
</div>
|
</div>
|
||||||
<div id="form_sheld">
|
<div id="form_sheld">
|
||||||
|
<div id="token_breakdown" style="display:none;">
|
||||||
|
<div>
|
||||||
|
<!-- Token Breakdown Goes Here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="dialogue_del_mes">
|
<div id="dialogue_del_mes">
|
||||||
<div id="dialogue_del_mes_ok" class="menu_button">Delete</div>
|
<div id="dialogue_del_mes_ok" class="menu_button">Delete</div>
|
||||||
<div id="dialogue_del_mes_cancel" class="menu_button">Cancel</div>
|
<div id="dialogue_del_mes_cancel" class="menu_button">Cancel</div>
|
||||||
@ -2430,9 +2505,9 @@
|
|||||||
<textarea id="send_textarea" placeholder="Not connected to API!" name="text"></textarea>
|
<textarea id="send_textarea" placeholder="Not connected to API!" name="text"></textarea>
|
||||||
<div id="send_but_sheld">
|
<div id="send_but_sheld">
|
||||||
<div id="loading_mes">
|
<div id="loading_mes">
|
||||||
<div alt="" class="fa-solid fa-hourglass-half"></div>
|
<div title="Loading" class="fa-solid fa-hourglass-half"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="send_but" class="fa-solid fa-feather-pointed"></div>
|
<div id="send_but" class="fa-solid fa-feather-pointed" title="Send a message"></div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -2449,6 +2524,10 @@
|
|||||||
<i class="fa-lg fa-solid fa-bookmark"></i>
|
<i class="fa-lg fa-solid fa-bookmark"></i>
|
||||||
<span>Save bookmark</span>
|
<span>Save bookmark</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a id="option_toggle_AN">
|
||||||
|
<i class="fa-lg fa-solid fa-note-sticky"></i>
|
||||||
|
<span>Open Author's Note</span>
|
||||||
|
</a>
|
||||||
<a id="option_convert_to_group">
|
<a id="option_convert_to_group">
|
||||||
<i class="fa-lg fa-solid fa-people-arrows"></i>
|
<i class="fa-lg fa-solid fa-people-arrows"></i>
|
||||||
<span>Convert to group</span>
|
<span>Convert to group</span>
|
||||||
@ -2487,6 +2566,9 @@
|
|||||||
<div id="avatar_zoom_popupheader" class="fa-solid fa-grip drag-grabber"></div>
|
<div id="avatar_zoom_popupheader" class="fa-solid fa-grip drag-grabber"></div>
|
||||||
<img id="zoomed_avatar" src="">
|
<img id="zoomed_avatar" src="">
|
||||||
</div>
|
</div>
|
||||||
|
<div id="rawPromptPopup" class="list-group">
|
||||||
|
<div id="rawPromptWrapper" class="tokenItemizingSubclass"></div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -393,26 +393,9 @@ _Lost API keys can't be restored! Make sure to keep it safe!_
|
|||||||
|
|
||||||
## Anchors
|
## Anchors
|
||||||
|
|
||||||
Anchors are used to increase the length of messages.
|
This feature is considered obsolete and has been removed.
|
||||||
There are two types of anchors: _Character Anchor_ and _Style Anchor_.
|
|
||||||
|
|
||||||
_Character Anchor_ - affects the character played by the AI by motivating it to write longer messages.
|
The use of the Author's Note extension is now a preferred way to add prompt injections of variable depth.
|
||||||
|
|
||||||
Looks like: `[Elaborate speaker]`
|
|
||||||
|
|
||||||
_Style Anchor_ - affects the entire AI model, motivating the AI to write longer messages even when it is not acting as the character.
|
|
||||||
|
|
||||||
Looks like: `[Writing style: very long messages]`
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
Anchors Order sets the location of anchors in the prompt, the first anchor in the order is much further back in the context and thus has less influence than second.
|
|
||||||
|
|
||||||
The second anchor is only turned on after 8-12 messages, because when the chat still only has a few messages, the first anchor creates enough effect on its own.
|
|
||||||
|
|
||||||
Sometimes an AI model may not perceive anchors correctly or the AI model already generates sufficiently long messages. For these cases, you can disable the anchors by unchecking their respective boxes.
|
|
||||||
|
|
||||||
_When using Pygmalion models these anchors are automatically disabled, since Pygmalion already generates long enough messages._
|
|
||||||
|
|
||||||
## Instruct Mode
|
## Instruct Mode
|
||||||
|
|
||||||
@ -594,6 +577,8 @@ Characters are drafted based on the order they are presented in group members li
|
|||||||
|
|
||||||
## Multigen
|
## Multigen
|
||||||
|
|
||||||
|
*This feature provides a pseudo-streaming functionality which conflicts with token streaming. When Multigen is enabled and generation API supports streaming, only Multigen streaming will be used.*
|
||||||
|
|
||||||
SillyTavern tries to create faster and longer responses by chaining the generation using smaller batches.
|
SillyTavern tries to create faster and longer responses by chaining the generation using smaller batches.
|
||||||
|
|
||||||
### Default settings:
|
### Default settings:
|
||||||
@ -614,6 +599,7 @@ Next batches = 30 tokens
|
|||||||
2. Character starts speaking for You.
|
2. Character starts speaking for You.
|
||||||
3. <|endoftext|> token reached.
|
3. <|endoftext|> token reached.
|
||||||
4. No text generated.
|
4. No text generated.
|
||||||
|
5. Stop sequence generated. (Instruct mode only)
|
||||||
|
|
||||||
## User Settings
|
## User Settings
|
||||||
|
|
||||||
|
1308
public/script.js
1308
public/script.js
File diff suppressed because it is too large
Load Diff
@ -30,11 +30,16 @@ import {
|
|||||||
import { sortByCssOrder } from "./utils.js";
|
import { sortByCssOrder } from "./utils.js";
|
||||||
|
|
||||||
var NavToggle = document.getElementById("nav-toggle");
|
var NavToggle = document.getElementById("nav-toggle");
|
||||||
|
|
||||||
var RPanelPin = document.getElementById("rm_button_panel_pin");
|
var RPanelPin = document.getElementById("rm_button_panel_pin");
|
||||||
var LPanelPin = document.getElementById("lm_button_panel_pin");
|
var LPanelPin = document.getElementById("lm_button_panel_pin");
|
||||||
var SelectedCharacterTab = document.getElementById("rm_button_selected_ch");
|
var WIPanelPin = document.getElementById("WI_panel_pin");
|
||||||
|
|
||||||
var RightNavPanel = document.getElementById("right-nav-panel");
|
var RightNavPanel = document.getElementById("right-nav-panel");
|
||||||
var LeftNavPanel = document.getElementById("left-nav-panel")
|
var LeftNavPanel = document.getElementById("left-nav-panel");
|
||||||
|
var WorldInfo = document.getElementById("WorldInfo");
|
||||||
|
|
||||||
|
var SelectedCharacterTab = document.getElementById("rm_button_selected_ch");
|
||||||
var AdvancedCharDefsPopup = document.getElementById("character_popup");
|
var AdvancedCharDefsPopup = document.getElementById("character_popup");
|
||||||
var ConfirmationPopup = document.getElementById("dialogue_popup");
|
var ConfirmationPopup = document.getElementById("dialogue_popup");
|
||||||
var AutoConnectCheckbox = document.getElementById("auto-connect-checkbox");
|
var AutoConnectCheckbox = document.getElementById("auto-connect-checkbox");
|
||||||
@ -101,10 +106,20 @@ function waitForElement(querySelector, timeout) {
|
|||||||
waitForElement("#expression-image", 10000).then(function () {
|
waitForElement("#expression-image", 10000).then(function () {
|
||||||
|
|
||||||
dragElement(document.getElementById("expression-holder"));
|
dragElement(document.getElementById("expression-holder"));
|
||||||
|
dragElement(document.getElementById("floatingPrompt"));
|
||||||
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
console.log("expression holder not loaded yet");
|
console.log("expression holder not loaded yet");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
waitForElement("#floatingPrompt", 10000).then(function () {
|
||||||
|
|
||||||
|
dragElement(document.getElementById("floatingPrompt"));
|
||||||
|
|
||||||
|
}).catch(() => {
|
||||||
|
console.log("floating prompt box not loaded yet");
|
||||||
|
});
|
||||||
|
|
||||||
// Device detection
|
// Device detection
|
||||||
const deviceInfo = await getDeviceInfo();
|
const deviceInfo = await getDeviceInfo();
|
||||||
|
|
||||||
@ -412,23 +427,18 @@ function OpenNavPanels() {
|
|||||||
if (LoadLocalBool("NavLockOn") == true && LoadLocalBool("NavOpened") == true) {
|
if (LoadLocalBool("NavLockOn") == true && LoadLocalBool("NavOpened") == true) {
|
||||||
//console.log("RA -- clicking right nav to open");
|
//console.log("RA -- clicking right nav to open");
|
||||||
$("#rightNavDrawerIcon").click();
|
$("#rightNavDrawerIcon").click();
|
||||||
} else {
|
|
||||||
/* console.log('didnt see reason to open right nav on load: R-nav locked? ' +
|
|
||||||
LoadLocalBool("NavLockOn")
|
|
||||||
+ ' R-nav was open before? ' +
|
|
||||||
LoadLocalBool("NavOpened" == true)); */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//auto-open L nav if locked and previously open
|
//auto-open L nav if locked and previously open
|
||||||
|
|
||||||
if (LoadLocalBool("LNavLockOn") == true && LoadLocalBool("LNavOpened") == true) {
|
if (LoadLocalBool("LNavLockOn") == true && LoadLocalBool("LNavOpened") == true) {
|
||||||
console.log("RA -- clicking left nav to open");
|
console.log("RA -- clicking left nav to open");
|
||||||
$("#leftNavDrawerIcon").click();
|
$("#leftNavDrawerIcon").click();
|
||||||
} else {
|
}
|
||||||
/* console.log('didnt see reason to open left nav on load: L-Nav Locked? ' +
|
|
||||||
LoadLocalBool("LNavLockOn")
|
//auto-open WI if locked and previously open
|
||||||
+ ' L-nav was open before? ' +
|
if (LoadLocalBool("WINavLockOn") == true && LoadLocalBool("WINavOpened") == true) {
|
||||||
LoadLocalBool("LNavOpened" == true)); */
|
console.log("RA -- clicking WI to open");
|
||||||
|
$("#WIDrawerIcon").click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,10 +448,12 @@ dragElement(document.getElementById("sheld"));
|
|||||||
dragElement(document.getElementById("left-nav-panel"));
|
dragElement(document.getElementById("left-nav-panel"));
|
||||||
dragElement(document.getElementById("right-nav-panel"));
|
dragElement(document.getElementById("right-nav-panel"));
|
||||||
dragElement(document.getElementById("avatar_zoom_popup"));
|
dragElement(document.getElementById("avatar_zoom_popup"));
|
||||||
|
dragElement(document.getElementById("WorldInfo"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function dragElement(elmnt) {
|
function dragElement(elmnt) {
|
||||||
|
|
||||||
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
|
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
|
||||||
if (document.getElementById(elmnt.id + "header")) { //ex: id="sheldheader"
|
if (document.getElementById(elmnt.id + "header")) { //ex: id="sheldheader"
|
||||||
// if present, the header is where you move the DIV from, but this overrides everything else:
|
// if present, the header is where you move the DIV from, but this overrides everything else:
|
||||||
@ -452,6 +464,7 @@ function dragElement(elmnt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dragMouseDown(e) {
|
function dragMouseDown(e) {
|
||||||
|
//console.log(e);
|
||||||
e = e || window.event;
|
e = e || window.event;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
// get the mouse cursor position at startup:
|
// get the mouse cursor position at startup:
|
||||||
@ -546,6 +559,7 @@ function dragElement(elmnt) {
|
|||||||
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
|
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
|
||||||
$(elmnt).css("bottom", "unset");
|
$(elmnt).css("bottom", "unset");
|
||||||
$(elmnt).css("right", "unset");
|
$(elmnt).css("right", "unset");
|
||||||
|
$(elmnt).css("margin", "unset");
|
||||||
|
|
||||||
/* console.log(`
|
/* console.log(`
|
||||||
offsetLeft: ${elmnt.offsetLeft}, offsetTop: ${elmnt.offsetTop}
|
offsetLeft: ${elmnt.offsetLeft}, offsetTop: ${elmnt.offsetTop}
|
||||||
@ -614,7 +628,7 @@ $("document").ready(function () {
|
|||||||
|
|
||||||
if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {
|
if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {
|
||||||
$(RightNavPanel).slideToggle(200, "swing");
|
$(RightNavPanel).slideToggle(200, "swing");
|
||||||
$(rightNavDrawerIcon).toggleClass('openIcon closedIcon');
|
//$(rightNavDrawerIcon).toggleClass('openIcon closedIcon');
|
||||||
$(RightNavPanel).toggleClass('openDrawer closedDrawer');
|
$(RightNavPanel).toggleClass('openDrawer closedDrawer');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -630,12 +644,30 @@ $("document").ready(function () {
|
|||||||
|
|
||||||
if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {
|
if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {
|
||||||
$(LeftNavPanel).slideToggle(200, "swing");
|
$(LeftNavPanel).slideToggle(200, "swing");
|
||||||
$(leftNavDrawerIcon).toggleClass('openIcon closedIcon');
|
//$(leftNavDrawerIcon).toggleClass('openIcon closedIcon');
|
||||||
$(LeftNavPanel).toggleClass('openDrawer closedDrawer');
|
$(LeftNavPanel).toggleClass('openDrawer closedDrawer');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(WIPanelPin).on("click", function () {
|
||||||
|
SaveLocal("WINavLockOn", $(WIPanelPin).prop("checked"));
|
||||||
|
if ($(WIPanelPin).prop("checked") == true) {
|
||||||
|
console.log('adding pin class to WI');
|
||||||
|
$(WorldInfo).addClass('pinnedOpen');
|
||||||
|
} else {
|
||||||
|
console.log('removing pin class from WI');
|
||||||
|
$(WorldInfo).removeClass('pinnedOpen');
|
||||||
|
|
||||||
|
if ($(WorldInfo).hasClass('openDrawer') && $('.openDrawer').length > 1) {
|
||||||
|
console.log('closing WI after lock removal');
|
||||||
|
$(WorldInfo).slideToggle(200, "swing");
|
||||||
|
//$(WorldInfoDrawerIcon).toggleClass('openIcon closedIcon');
|
||||||
|
$(WorldInfo).toggleClass('openDrawer closedDrawer');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// read the state of right Nav Lock and apply to rightnav classlist
|
// read the state of right Nav Lock and apply to rightnav classlist
|
||||||
$(RPanelPin).prop('checked', LoadLocalBool("NavLockOn"));
|
$(RPanelPin).prop('checked', LoadLocalBool("NavLockOn"));
|
||||||
if (LoadLocalBool("NavLockOn") == true) {
|
if (LoadLocalBool("NavLockOn") == true) {
|
||||||
@ -657,6 +689,18 @@ $("document").ready(function () {
|
|||||||
$(LeftNavPanel).addClass('pinnedOpen');
|
$(LeftNavPanel).addClass('pinnedOpen');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read the state of left Nav Lock and apply to leftnav classlist
|
||||||
|
$(WIPanelPin).prop('checked', LoadLocalBool("WINavLockOn"));
|
||||||
|
if (LoadLocalBool("WINavLockOn") == true) {
|
||||||
|
//console.log('setting pin class via local var');
|
||||||
|
$(WorldInfo).addClass('pinnedOpen');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($(WIPanelPin).prop('checked' == true)) {
|
||||||
|
console.log('setting pin class via checkbox state');
|
||||||
|
$(WorldInfo).addClass('pinnedOpen');
|
||||||
|
}
|
||||||
|
|
||||||
//save state of Right nav being open or closed
|
//save state of Right nav being open or closed
|
||||||
$("#rightNavDrawerIcon").on("click", function () {
|
$("#rightNavDrawerIcon").on("click", function () {
|
||||||
if (!$("#rightNavDrawerIcon").hasClass('openIcon')) {
|
if (!$("#rightNavDrawerIcon").hasClass('openIcon')) {
|
||||||
@ -671,6 +715,13 @@ $("document").ready(function () {
|
|||||||
} else { SaveLocal('LNavOpened', 'false'); }
|
} else { SaveLocal('LNavOpened', 'false'); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//save state of Left nav being open or closed
|
||||||
|
$("#WorldInfo").on("click", function () {
|
||||||
|
if (!$("#WorldInfo").hasClass('openIcon')) {
|
||||||
|
SaveLocal('WINavOpened', 'true');
|
||||||
|
} else { SaveLocal('WINavOpened', 'false'); }
|
||||||
|
});
|
||||||
|
|
||||||
var chatbarInFocus = false;
|
var chatbarInFocus = false;
|
||||||
$('#send_textarea').focus(function () {
|
$('#send_textarea').focus(function () {
|
||||||
chatbarInFocus = true;
|
chatbarInFocus = true;
|
||||||
|
71
public/scripts/eventemitter.js
Normal file
71
public/scripts/eventemitter.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/* Polyfill indexOf. */
|
||||||
|
var indexOf;
|
||||||
|
|
||||||
|
if (typeof Array.prototype.indexOf === 'function') {
|
||||||
|
indexOf = function (haystack, needle) {
|
||||||
|
return haystack.indexOf(needle);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
indexOf = function (haystack, needle) {
|
||||||
|
var i = 0, length = haystack.length, idx = -1, found = false;
|
||||||
|
|
||||||
|
while (i < length && !found) {
|
||||||
|
if (haystack[i] === needle) {
|
||||||
|
idx = i;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Polyfill EventEmitter. */
|
||||||
|
var EventEmitter = function () {
|
||||||
|
this.events = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
EventEmitter.prototype.on = function (event, listener) {
|
||||||
|
if (typeof this.events[event] !== 'object') {
|
||||||
|
this.events[event] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.events[event].push(listener);
|
||||||
|
};
|
||||||
|
|
||||||
|
EventEmitter.prototype.removeListener = function (event, listener) {
|
||||||
|
var idx;
|
||||||
|
|
||||||
|
if (typeof this.events[event] === 'object') {
|
||||||
|
idx = indexOf(this.events[event], listener);
|
||||||
|
|
||||||
|
if (idx > -1) {
|
||||||
|
this.events[event].splice(idx, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EventEmitter.prototype.emit = function (event) {
|
||||||
|
var i, listeners, length, args = [].slice.call(arguments, 1);
|
||||||
|
|
||||||
|
if (typeof this.events[event] === 'object') {
|
||||||
|
listeners = this.events[event].slice();
|
||||||
|
length = listeners.length;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
listeners[i].apply(this, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EventEmitter.prototype.once = function (event, listener) {
|
||||||
|
this.on(event, function g () {
|
||||||
|
this.removeListener(event, g);
|
||||||
|
listener.apply(this, arguments);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { EventEmitter }
|
@ -1,4 +1,4 @@
|
|||||||
import { callPopup, saveSettings, saveSettingsDebounced } from "../script.js";
|
import { callPopup, eventSource, event_types, saveSettings, saveSettingsDebounced } from "../script.js";
|
||||||
import { isSubsetOf } from "./utils.js";
|
import { isSubsetOf } from "./utils.js";
|
||||||
export {
|
export {
|
||||||
getContext,
|
getContext,
|
||||||
@ -162,6 +162,7 @@ async function connectToApi(baseUrl) {
|
|||||||
const data = await getExtensionsResult.json();
|
const data = await getExtensionsResult.json();
|
||||||
modules = data.modules;
|
modules = data.modules;
|
||||||
await activateExtensions();
|
await activateExtensions();
|
||||||
|
eventSource.emit(event_types.EXTRAS_CONNECTED, modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStatus(getExtensionsResult.ok);
|
updateStatus(getExtensionsResult.ok);
|
||||||
|
@ -96,6 +96,7 @@ $(document).ready(function () {
|
|||||||
function addSendPictureButton() {
|
function addSendPictureButton() {
|
||||||
const sendButton = document.createElement('div');
|
const sendButton = document.createElement('div');
|
||||||
sendButton.id = 'send_picture';
|
sendButton.id = 'send_picture';
|
||||||
|
sendButton.title = 'Send a picture to chat';
|
||||||
sendButton.classList.add('fa-solid');
|
sendButton.classList.add('fa-solid');
|
||||||
$(sendButton).hide();
|
$(sendButton).hide();
|
||||||
$(sendButton).on('click', () => $('#img_file').click());
|
$(sendButton).on('click', () => $('#img_file').click());
|
||||||
|
@ -29,7 +29,7 @@ async function doDiceRoll() {
|
|||||||
|
|
||||||
function addDiceRollButton() {
|
function addDiceRollButton() {
|
||||||
const buttonHtml = `
|
const buttonHtml = `
|
||||||
<div id="roll_dice" class="fa-solid fa-dice" /></div>
|
<div id="roll_dice" class="fa-solid fa-dice" title="Roll the dice" /></div>
|
||||||
`;
|
`;
|
||||||
const dropdownHtml = `
|
const dropdownHtml = `
|
||||||
<div id="dice_dropdown">
|
<div id="dice_dropdown">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { chat_metadata, saveSettingsDebounced } from "../../../script.js";
|
import { chat_metadata, saveSettingsDebounced } from "../../../script.js";
|
||||||
import { extension_settings, getContext } from "../../extensions.js";
|
import { extension_settings, getContext } from "../../extensions.js";
|
||||||
|
import { registerSlashCommand } from "../../slash-commands.js";
|
||||||
import { debounce } from "../../utils.js";
|
import { debounce } from "../../utils.js";
|
||||||
export { MODULE_NAME };
|
export { MODULE_NAME };
|
||||||
|
|
||||||
@ -19,6 +20,10 @@ const metadata_keys = {
|
|||||||
position: 'note_position',
|
position: 'note_position',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setNoteCommand(_, text) {
|
||||||
|
$('#extension_floating_prompt').val(text).trigger('input');
|
||||||
|
}
|
||||||
|
|
||||||
async function onExtensionFloatingPromptInput() {
|
async function onExtensionFloatingPromptInput() {
|
||||||
chat_metadata[metadata_keys.prompt] = $(this).val();
|
chat_metadata[metadata_keys.prompt] = $(this).val();
|
||||||
saveMetadataDebounced();
|
saveMetadataDebounced();
|
||||||
@ -100,7 +105,7 @@ async function moduleWorker() {
|
|||||||
|
|
||||||
if (lastMessageNumber <= 0 || chat_metadata[metadata_keys.interval] <= 0) {
|
if (lastMessageNumber <= 0 || chat_metadata[metadata_keys.interval] <= 0) {
|
||||||
context.setExtensionPrompt(MODULE_NAME, '');
|
context.setExtensionPrompt(MODULE_NAME, '');
|
||||||
$('#extension_floating_counter').text('No');
|
$('#extension_floating_counter').text('(disabled)');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,57 +115,67 @@ async function moduleWorker() {
|
|||||||
const shouldAddPrompt = messagesTillInsertion == 0;
|
const shouldAddPrompt = messagesTillInsertion == 0;
|
||||||
const prompt = shouldAddPrompt ? $('#extension_floating_prompt').val() : '';
|
const prompt = shouldAddPrompt ? $('#extension_floating_prompt').val() : '';
|
||||||
context.setExtensionPrompt(MODULE_NAME, prompt, chat_metadata[metadata_keys.position], chat_metadata[metadata_keys.depth]);
|
context.setExtensionPrompt(MODULE_NAME, prompt, chat_metadata[metadata_keys.position], chat_metadata[metadata_keys.depth]);
|
||||||
$('#extension_floating_counter').text(shouldAddPrompt ? 'This' : messagesTillInsertion);
|
$('#extension_floating_counter').text(shouldAddPrompt ? '0' : messagesTillInsertion);
|
||||||
}
|
}
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
function addExtensionsSettings() {
|
function addExtensionsSettings() {
|
||||||
const settingsHtml = `
|
const settingsHtml = `
|
||||||
<div class="floating_prompt_settings">
|
<div id="floatingPrompt" class="drawer-content flexGap5">
|
||||||
<div class="inline-drawer">
|
<div id="floatingPromptheader" class="fa-solid fa-grip drag-grabber"></div>
|
||||||
<div class="inline-drawer-toggle inline-drawer-header">
|
<div name="floatingPromptHolder">
|
||||||
<b>Author's Note / Character Bias</b>
|
<div class="inline-drawer">
|
||||||
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
<div id="ANBlockToggle" class="inline-drawer-toggle inline-drawer-header">
|
||||||
</div>
|
<b>Author's Note</b>
|
||||||
<div class="inline-drawer-content">
|
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||||
<small>
|
|
||||||
Your notes are saved <b>PER CHAT</b>. When you start a new chat, you'll see the default / empty note.<br>
|
|
||||||
Saving a bookmark will copy your note to a bookmark chat. Making changes to it won't update the note in a parent chat.<br>
|
|
||||||
</small>
|
|
||||||
<label for="extension_floating_prompt">Append the following text:</label>
|
|
||||||
<textarea id="extension_floating_prompt" class="text_pole" rows="8"></textarea>
|
|
||||||
<div class="floating_prompt_radio_group">
|
|
||||||
<label>
|
|
||||||
<input type="radio" name="extension_floating_position" value="0" />
|
|
||||||
After scenario
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input type="radio" name="extension_floating_position" value="1" />
|
|
||||||
In-chat
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<label for="extension_floating_interval">Every N messages <b>you</b> send (set to 0 to disable):</label>
|
|
||||||
<input id="extension_floating_interval" class="text_pole" type="number" min="0" max="999" />
|
|
||||||
<label for="extension_floating_interval">Insertion depth (for in-chat positioning):</label>
|
|
||||||
<input id="extension_floating_depth" class="text_pole" type="number" min="0" max="99" />
|
|
||||||
<span>Appending to the prompt in next: <span id="extension_floating_counter">No</span> message(s)</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="inline-drawer">
|
|
||||||
<div class="inline-drawer-toggle inline-drawer-header">
|
|
||||||
<b>Default note for new chats</b>
|
|
||||||
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="inline-drawer-content">
|
<div class="inline-drawer-content">
|
||||||
<label for="extension_floating_default">Default Author's Note</label>
|
<small>
|
||||||
<textarea id="extension_floating_default" class="text_pole" rows="8"
|
<b>Unique to this chat</b>.<br>
|
||||||
placeholder="Example:\n[Scenario: wacky adventures; Genre: romantic comedy; Style: verbose, creative]"></textarea>
|
Bookmarks inherit the Note from their parent, and can be changed individually after that.<br>
|
||||||
|
</small>
|
||||||
|
|
||||||
|
<textarea id="extension_floating_prompt" class="text_pole" rows="8"></textarea>
|
||||||
|
|
||||||
|
<div class="floating_prompt_radio_group">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="extension_floating_position" value="0" />
|
||||||
|
After scenario
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="extension_floating_position" value="1" />
|
||||||
|
In-chat @ Depth <input id="extension_floating_depth" class="text_pole widthUnset" type="number" min="0" max="99" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<!--<label for="extension_floating_interval">In-Chat Insertion Depth</label>-->
|
||||||
|
|
||||||
|
<label for="extension_floating_interval">Insertion Frequency</label>
|
||||||
|
|
||||||
|
<input id="extension_floating_interval" class="text_pole widthUnset" type="number" min="0" max="999" /><small> (0 = Disable)</small>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<span>User inputs until next insertion: <span id="extension_floating_counter">(disabled)</span></span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr class="sysHR">
|
||||||
|
<div class="inline-drawer">
|
||||||
|
<div id="defaultANBlockToggle" class="inline-drawer-toggle inline-drawer-header">
|
||||||
|
<b>Default Author's Note</b>
|
||||||
|
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||||
|
</div>
|
||||||
|
<div class="inline-drawer-content">
|
||||||
|
<small>Will be automatically added as the Author's Note for all new chats.</small>
|
||||||
|
|
||||||
|
<textarea id="extension_floating_default" class="text_pole" rows="8"
|
||||||
|
placeholder="Example:\n[Scenario: wacky adventures; Genre: romantic comedy; Style: verbose, creative]"></textarea>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
$('#extensions_settings').append(settingsHtml);
|
$('#movingDivs').append(settingsHtml);
|
||||||
$('#extension_floating_prompt').on('input', onExtensionFloatingPromptInput);
|
$('#extension_floating_prompt').on('input', onExtensionFloatingPromptInput);
|
||||||
$('#extension_floating_interval').on('input', onExtensionFloatingIntervalInput);
|
$('#extension_floating_interval').on('input', onExtensionFloatingIntervalInput);
|
||||||
$('#extension_floating_depth').on('input', onExtensionFloatingDepthInput);
|
$('#extension_floating_depth').on('input', onExtensionFloatingDepthInput);
|
||||||
@ -170,4 +185,5 @@ async function moduleWorker() {
|
|||||||
|
|
||||||
addExtensionsSettings();
|
addExtensionsSettings();
|
||||||
setInterval(moduleWorkerWrapper, UPDATE_INTERVAL);
|
setInterval(moduleWorkerWrapper, UPDATE_INTERVAL);
|
||||||
|
registerSlashCommand('note', setNoteCommand, [], " – sets an author's note for the currently selected chat", true, true);
|
||||||
})();
|
})();
|
@ -1,4 +1,26 @@
|
|||||||
.floating_prompt_settings {
|
#floatingPrompt {
|
||||||
|
overflow-y: auto;
|
||||||
|
max-width: 90svw;
|
||||||
|
max-height: 90svh;
|
||||||
|
min-width: 100px;
|
||||||
|
min-height: 100px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid var(--white30a);
|
||||||
|
position: fixed;
|
||||||
|
padding: 10px;
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 0 10px var(--black70a);
|
||||||
|
z-index: 3000;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
margin: 0;
|
||||||
|
right: unset;
|
||||||
|
width: calc(((100svw - var(--sheldWidth)) / 2) - 1px);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.floating_prompt_radio_group {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@ -12,8 +34,3 @@
|
|||||||
font-size: calc(var(--mainFontSize) * 0.9);
|
font-size: calc(var(--mainFontSize) * 0.9);
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.floating_prompt_radio_group {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
@ -3,9 +3,13 @@ import {
|
|||||||
saveSettingsDebounced,
|
saveSettingsDebounced,
|
||||||
systemUserName,
|
systemUserName,
|
||||||
hideSwipeButtons,
|
hideSwipeButtons,
|
||||||
showSwipeButtons
|
showSwipeButtons,
|
||||||
|
callPopup,
|
||||||
|
getRequestHeaders,
|
||||||
|
event_types,
|
||||||
|
eventSource
|
||||||
} from "../../../script.js";
|
} from "../../../script.js";
|
||||||
import { getApiUrl, getContext, extension_settings, defaultRequestArgs } from "../../extensions.js";
|
import { getApiUrl, getContext, extension_settings, defaultRequestArgs, modules } from "../../extensions.js";
|
||||||
import { stringFormat, initScrollHeight, resetScrollHeight } from "../../utils.js";
|
import { stringFormat, initScrollHeight, resetScrollHeight } from "../../utils.js";
|
||||||
export { MODULE_NAME };
|
export { MODULE_NAME };
|
||||||
|
|
||||||
@ -94,6 +98,9 @@ const defaultSettings = {
|
|||||||
negative_prompt: 'lowres, bad anatomy, bad hands, text, error, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry',
|
negative_prompt: 'lowres, bad anatomy, bad hands, text, error, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry',
|
||||||
sampler: 'DDIM',
|
sampler: 'DDIM',
|
||||||
model: '',
|
model: '',
|
||||||
|
|
||||||
|
horde: false,
|
||||||
|
horde_nsfw: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadSettings() {
|
async function loadSettings() {
|
||||||
@ -107,11 +114,10 @@ async function loadSettings() {
|
|||||||
$('#sd_negative_prompt').val(extension_settings.sd.negative_prompt).trigger('input');
|
$('#sd_negative_prompt').val(extension_settings.sd.negative_prompt).trigger('input');
|
||||||
$('#sd_width').val(extension_settings.sd.width).trigger('input');
|
$('#sd_width').val(extension_settings.sd.width).trigger('input');
|
||||||
$('#sd_height').val(extension_settings.sd.height).trigger('input');
|
$('#sd_height').val(extension_settings.sd.height).trigger('input');
|
||||||
|
$('#sd_horde').prop('checked', extension_settings.sd.horde);
|
||||||
|
$('#sd_horde_nsfw').prop('checked', extension_settings.sd.horde_nsfw);
|
||||||
|
|
||||||
await Promise.all([loadSamplers(), loadModels()]);
|
await Promise.all([loadSamplers(), loadModels()]);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onScaleInput() {
|
function onScaleInput() {
|
||||||
@ -155,10 +161,29 @@ function onHeightInput() {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function onHordeInput() {
|
||||||
|
extension_settings.sd.model = null;
|
||||||
|
extension_settings.sd.sampler = null;
|
||||||
|
extension_settings.sd.horde = !!$(this).prop('checked');
|
||||||
|
saveSettingsDebounced();
|
||||||
|
await Promise.all([loadModels(), loadSamplers()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onHordeNsfwInput() {
|
||||||
|
extension_settings.sd.horde_nsfw = !!$(this).prop('checked');
|
||||||
|
saveSettingsDebounced();
|
||||||
|
}
|
||||||
|
|
||||||
async function onModelChange() {
|
async function onModelChange() {
|
||||||
extension_settings.sd.model = $('#sd_model').find(':selected').val();
|
extension_settings.sd.model = $('#sd_model').find(':selected').val();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
|
||||||
|
if (extension_settings.sd.horde == false) {
|
||||||
|
await updateExtrasRemoteModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateExtrasRemoteModel() {
|
||||||
const url = new URL(getApiUrl());
|
const url = new URL(getApiUrl());
|
||||||
url.pathname = '/api/image/model';
|
url.pathname = '/api/image/model';
|
||||||
const getCurrentModelResult = await fetch(url, {
|
const getCurrentModelResult = await fetch(url, {
|
||||||
@ -173,25 +198,94 @@ async function onModelChange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadSamplers() {
|
async function loadSamplers() {
|
||||||
|
$('#sd_sampler').empty();
|
||||||
|
let samplers = [];
|
||||||
|
|
||||||
|
if (extension_settings.sd.horde) {
|
||||||
|
samplers = await loadHordeSamplers();
|
||||||
|
} else {
|
||||||
|
samplers = await loadExtrasSamplers();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const sampler of samplers) {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.innerText = sampler;
|
||||||
|
option.value = sampler;
|
||||||
|
option.selected = sampler === extension_settings.sd.sampler;
|
||||||
|
$('#sd_sampler').append(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadHordeSamplers() {
|
||||||
|
const result = await fetch('/horde_samplers', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: getRequestHeaders(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.ok) {
|
||||||
|
const data = await result.json();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadExtrasSamplers() {
|
||||||
|
if (!modules.includes('sd')) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
const url = new URL(getApiUrl());
|
const url = new URL(getApiUrl());
|
||||||
url.pathname = '/api/image/samplers';
|
url.pathname = '/api/image/samplers';
|
||||||
const result = await fetch(url, defaultRequestArgs);
|
const result = await fetch(url, defaultRequestArgs);
|
||||||
|
|
||||||
if (result.ok) {
|
if (result.ok) {
|
||||||
const data = await result.json();
|
const data = await result.json();
|
||||||
const samplers = data.samplers;
|
return data.samplers;
|
||||||
|
|
||||||
for (const sampler of samplers) {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.innerText = sampler;
|
|
||||||
option.value = sampler;
|
|
||||||
option.selected = sampler === extension_settings.sd.sampler;
|
|
||||||
$('#sd_sampler').append(option);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadModels() {
|
async function loadModels() {
|
||||||
|
$('#sd_model').empty();
|
||||||
|
let models = [];
|
||||||
|
|
||||||
|
if (extension_settings.sd.horde) {
|
||||||
|
models = await loadHordeModels();
|
||||||
|
} else {
|
||||||
|
models = await loadExtrasModels();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const model of models) {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.innerText = model.text;
|
||||||
|
option.value = model.value;
|
||||||
|
option.selected = model.value === extension_settings.sd.model;
|
||||||
|
$('#sd_model').append(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadHordeModels() {
|
||||||
|
const result = await fetch('/horde_models', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: getRequestHeaders(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.ok) {
|
||||||
|
const data = await result.json();
|
||||||
|
const models = data.map(x => ({ value: x.name, text: `${x.name} (ETA: ${x.eta}s, Queue: ${x.queued}, Workers: ${x.count})` }));
|
||||||
|
return models;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadExtrasModels() {
|
||||||
|
if (!modules.includes('sd')) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
const url = new URL(getApiUrl());
|
const url = new URL(getApiUrl());
|
||||||
url.pathname = '/api/image/model';
|
url.pathname = '/api/image/model';
|
||||||
const getCurrentModelResult = await fetch(url, defaultRequestArgs);
|
const getCurrentModelResult = await fetch(url, defaultRequestArgs);
|
||||||
@ -206,16 +300,11 @@ async function loadModels() {
|
|||||||
|
|
||||||
if (getModelsResult.ok) {
|
if (getModelsResult.ok) {
|
||||||
const data = await getModelsResult.json();
|
const data = await getModelsResult.json();
|
||||||
const models = data.models;
|
const view_models = data.models.map(x => ({ value: x, text: x }));
|
||||||
|
return view_models;
|
||||||
for (const model of models) {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.innerText = model;
|
|
||||||
option.value = model;
|
|
||||||
option.selected = model === extension_settings.sd.model;
|
|
||||||
$('#sd_model').append(option);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGenerationType(prompt) {
|
function getGenerationType(prompt) {
|
||||||
@ -257,6 +346,14 @@ async function generatePicture(_, trigger) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!modules.includes('sd') && !extension_settings.sd.horde) {
|
||||||
|
callPopup("Extensions API is not connected or doesn't provide SD module. Enable Stable Horde to generate images.", 'text');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
extension_settings.sd.sampler = $('#sd_sampler').find(':selected').val();
|
||||||
|
extension_settings.sd.model = $('#sd_model').find(':selected').val();
|
||||||
|
|
||||||
trigger = trigger.trim();
|
trigger = trigger.trim();
|
||||||
const generationMode = getGenerationType(trigger);
|
const generationMode = getGenerationType(trigger);
|
||||||
console.log('Generation mode', generationMode, 'triggered with', trigger);
|
console.log('Generation mode', generationMode, 'triggered with', trigger);
|
||||||
@ -279,30 +376,10 @@ async function generatePicture(_, trigger) {
|
|||||||
|
|
||||||
console.log('Processed Stable Diffusion prompt:', prompt);
|
console.log('Processed Stable Diffusion prompt:', prompt);
|
||||||
|
|
||||||
const url = new URL(getApiUrl());
|
if (extension_settings.sd.horde) {
|
||||||
url.pathname = '/api/image';
|
await generateHordeImage(prompt);
|
||||||
const result = await fetch(url, {
|
} else {
|
||||||
method: 'POST',
|
await generateExtrasImage(prompt);
|
||||||
headers: postHeaders,
|
|
||||||
body: JSON.stringify({
|
|
||||||
prompt: prompt,
|
|
||||||
sampler: extension_settings.sd.sampler,
|
|
||||||
steps: extension_settings.sd.steps,
|
|
||||||
scale: extension_settings.sd.scale,
|
|
||||||
width: extension_settings.sd.width,
|
|
||||||
height: extension_settings.sd.height,
|
|
||||||
prompt_prefix: extension_settings.sd.prompt_prefix,
|
|
||||||
negative_prompt: extension_settings.sd.negative_prompt,
|
|
||||||
restore_faces: true,
|
|
||||||
face_restoration_model: 'GFPGAN',
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result.ok) {
|
|
||||||
const data = await result.json();
|
|
||||||
const base64Image = `data:image/jpeg;base64,${data.image}`;
|
|
||||||
sendMessage(prompt, base64Image);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.trace(err);
|
console.trace(err);
|
||||||
@ -314,6 +391,62 @@ async function generatePicture(_, trigger) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function generateExtrasImage(prompt) {
|
||||||
|
const url = new URL(getApiUrl());
|
||||||
|
url.pathname = '/api/image';
|
||||||
|
const result = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: postHeaders,
|
||||||
|
body: JSON.stringify({
|
||||||
|
prompt: prompt,
|
||||||
|
sampler: extension_settings.sd.sampler,
|
||||||
|
steps: extension_settings.sd.steps,
|
||||||
|
scale: extension_settings.sd.scale,
|
||||||
|
width: extension_settings.sd.width,
|
||||||
|
height: extension_settings.sd.height,
|
||||||
|
prompt_prefix: extension_settings.sd.prompt_prefix,
|
||||||
|
negative_prompt: extension_settings.sd.negative_prompt,
|
||||||
|
restore_faces: true,
|
||||||
|
face_restoration_model: 'GFPGAN',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.ok) {
|
||||||
|
const data = await result.json();
|
||||||
|
const base64Image = `data:image/jpeg;base64,${data.image}`;
|
||||||
|
sendMessage(prompt, base64Image);
|
||||||
|
} else {
|
||||||
|
callPopup('Image generation has failed. Please try again.', 'text');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateHordeImage(prompt) {
|
||||||
|
const result = await fetch('/horde_generateimage', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: getRequestHeaders(),
|
||||||
|
body: JSON.stringify({
|
||||||
|
prompt: prompt,
|
||||||
|
sampler: extension_settings.sd.sampler,
|
||||||
|
steps: extension_settings.sd.steps,
|
||||||
|
scale: extension_settings.sd.scale,
|
||||||
|
width: extension_settings.sd.width,
|
||||||
|
height: extension_settings.sd.height,
|
||||||
|
prompt_prefix: extension_settings.sd.prompt_prefix,
|
||||||
|
negative_prompt: extension_settings.sd.negative_prompt,
|
||||||
|
model: extension_settings.sd.model,
|
||||||
|
nsfw: extension_settings.sd.horde_nsfw,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.ok) {
|
||||||
|
const data = await result.text();
|
||||||
|
const base64Image = `data:image/webp;base64,${data}`;
|
||||||
|
sendMessage(prompt, base64Image);
|
||||||
|
} else {
|
||||||
|
callPopup('Image generation has failed. Please try again.', 'text');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function sendMessage(prompt, image) {
|
async function sendMessage(prompt, image) {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
const messageText = `[${context.name2} sends a picture that contains: ${prompt}]`;
|
const messageText = `[${context.name2} sends a picture that contains: ${prompt}]`;
|
||||||
@ -336,7 +469,7 @@ async function sendMessage(prompt, image) {
|
|||||||
|
|
||||||
function addSDGenButtons() {
|
function addSDGenButtons() {
|
||||||
const buttonHtml = `
|
const buttonHtml = `
|
||||||
<div id="sd_gen" class="fa-solid fa-paintbrush" /></div>
|
<div id="sd_gen" class="fa-solid fa-paintbrush" title="Trigger Stable Diffusion" /></div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const waitButtonHtml = `
|
const waitButtonHtml = `
|
||||||
@ -386,16 +519,6 @@ function addSDGenButtons() {
|
|||||||
async function moduleWorker() {
|
async function moduleWorker() {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
|
|
||||||
/* if (context.onlineStatus === 'no_connection') {
|
|
||||||
$('#sd_gen').hide(200);
|
|
||||||
} else if ($("#send_but").css('display') === 'flex') {
|
|
||||||
$('#sd_gen').show(200);
|
|
||||||
$("#sd_gen_wait").hide(200);
|
|
||||||
} else {
|
|
||||||
$('#sd_gen').hide(200);
|
|
||||||
$("#sd_gen_wait").show(200);
|
|
||||||
} */
|
|
||||||
|
|
||||||
context.onlineStatus === 'no_connection'
|
context.onlineStatus === 'no_connection'
|
||||||
? $('#sd_gen').hide(200)
|
? $('#sd_gen').hide(200)
|
||||||
: $('#sd_gen').show(200)
|
: $('#sd_gen').show(200)
|
||||||
@ -444,6 +567,16 @@ jQuery(async () => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="inline-drawer-content">
|
<div class="inline-drawer-content">
|
||||||
<small><i>Use slash commands to generate images. Type <span class="monospace">/help</span> in chat for more details</i></small>
|
<small><i>Use slash commands 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 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
|
||||||
|
</label>
|
||||||
<label for="sd_scale">CFG Scale (<span id="sd_scale_value"></span>)</label>
|
<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}" />
|
<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>
|
<label for="sd_steps">Sampling steps (<span id="sd_steps_value"></span>)</label>
|
||||||
@ -472,12 +605,17 @@ jQuery(async () => {
|
|||||||
$('#sd_negative_prompt').on('input', onNegativePromptInput);
|
$('#sd_negative_prompt').on('input', onNegativePromptInput);
|
||||||
$('#sd_width').on('input', onWidthInput);
|
$('#sd_width').on('input', onWidthInput);
|
||||||
$('#sd_height').on('input', onHeightInput);
|
$('#sd_height').on('input', onHeightInput);
|
||||||
|
$('#sd_horde').on('input', onHordeInput);
|
||||||
|
$('#sd_horde_nsfw').on('input', onHordeNsfwInput);
|
||||||
|
|
||||||
$('.sd_settings .inline-drawer-toggle').on('click', function () {
|
$('.sd_settings .inline-drawer-toggle').on('click', function () {
|
||||||
initScrollHeight($("#sd_prompt_prefix"));
|
initScrollHeight($("#sd_prompt_prefix"));
|
||||||
initScrollHeight($("#sd_negative_prompt"));
|
initScrollHeight($("#sd_negative_prompt"));
|
||||||
})
|
})
|
||||||
|
|
||||||
await loadSettings();
|
eventSource.on(event_types.EXTRAS_CONNECTED, async () => {
|
||||||
|
await Promise.all([loadSamplers(), loadModels()]);
|
||||||
|
});
|
||||||
|
|
||||||
|
await loadSettings();
|
||||||
});
|
});
|
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"display_name": "Stable Diffusion",
|
"display_name": "Stable Diffusion",
|
||||||
"loading_order": 10,
|
"loading_order": 10,
|
||||||
"requires": [
|
"requires": [],
|
||||||
|
"optional": [
|
||||||
"sd"
|
"sd"
|
||||||
],
|
],
|
||||||
"optional": [],
|
|
||||||
"js": "index.js",
|
"js": "index.js",
|
||||||
"css": "style.css",
|
"css": "style.css",
|
||||||
"author": "Cohee#1207",
|
"author": "Cohee#1207",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.sd_settings label {
|
.sd_settings label:not(.checkbox_label) {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,7 +16,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#sd_gen:hover {
|
#sd_gen:hover {
|
||||||
|
@ -7,6 +7,7 @@ class ElevenLabsTtsProvider {
|
|||||||
|
|
||||||
settings
|
settings
|
||||||
voices = []
|
voices = []
|
||||||
|
separator = ' ... ... ... '
|
||||||
|
|
||||||
get settings() {
|
get settings() {
|
||||||
return this.settings
|
return this.settings
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { callPopup, isMultigenEnabled, is_send_press, saveSettingsDebounced } from '../../../script.js'
|
import { callPopup, cancelTtsPlay, isMultigenEnabled, is_send_press, saveSettingsDebounced } from '../../../script.js'
|
||||||
import { extension_settings, getContext } from '../../extensions.js'
|
import { extension_settings, getContext } from '../../extensions.js'
|
||||||
import { getStringHash } from '../../utils.js'
|
import { getStringHash } from '../../utils.js'
|
||||||
import { ElevenLabsTtsProvider } from './elevenlabs.js'
|
import { ElevenLabsTtsProvider } from './elevenlabs.js'
|
||||||
@ -24,9 +24,47 @@ let ttsProviders = {
|
|||||||
let ttsProvider
|
let ttsProvider
|
||||||
let ttsProviderName
|
let ttsProviderName
|
||||||
|
|
||||||
|
async function onNarrateOneMessage() {
|
||||||
|
cancelTtsPlay();
|
||||||
|
const context = getContext();
|
||||||
|
const id = $(this).closest('.mes').attr('mesid');
|
||||||
|
const message = context.chat[id];
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTtsJob = null;
|
||||||
|
audioElement.pause();
|
||||||
|
audioElement.currentTime = 0;
|
||||||
|
ttsJobQueue.splice(0, ttsJobQueue.length);
|
||||||
|
audioJobQueue.splice(0, audioJobQueue.length);
|
||||||
|
ttsJobQueue.push(message);
|
||||||
|
moduleWorker();
|
||||||
|
}
|
||||||
|
|
||||||
|
let isWorkerBusy = false;
|
||||||
|
|
||||||
|
async function moduleWorkerWrapper() {
|
||||||
|
// Don't touch me I'm busy...
|
||||||
|
if (isWorkerBusy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I'm free. Let's update!
|
||||||
|
try {
|
||||||
|
isWorkerBusy = true;
|
||||||
|
await moduleWorker();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
isWorkerBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function moduleWorker() {
|
async function moduleWorker() {
|
||||||
// Primarily determinign when to add new chat to the TTS queue
|
// Primarily determinign when to add new chat to the TTS queue
|
||||||
const enabled = $('#tts_enabled').is(':checked')
|
const enabled = $('#tts_enabled').is(':checked')
|
||||||
|
$('body').toggleClass('tts', enabled);
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -163,7 +201,7 @@ function onAudioControlClicked() {
|
|||||||
|
|
||||||
function addAudioControl() {
|
function addAudioControl() {
|
||||||
$('#send_but_sheld').prepend('<div id="tts_media_control"/>')
|
$('#send_but_sheld').prepend('<div id="tts_media_control"/>')
|
||||||
$('#tts_media_control').on('click', onAudioControlClicked)
|
$('#tts_media_control').attr('title', 'TTS play/pause').on('click', onAudioControlClicked)
|
||||||
audioControl = document.getElementById('tts_media_control')
|
audioControl = document.getElementById('tts_media_control')
|
||||||
updateUiAudioPlayState()
|
updateUiAudioPlayState()
|
||||||
}
|
}
|
||||||
@ -247,7 +285,8 @@ async function processTtsQueue() {
|
|||||||
const special_quotes = /[“”]/g; // Extend this regex to include other special quotes
|
const special_quotes = /[“”]/g; // Extend this regex to include other special quotes
|
||||||
text = text.replace(special_quotes, '"');
|
text = text.replace(special_quotes, '"');
|
||||||
const matches = text.match(/".*?"/g); // Matches text inside double quotes, non-greedily
|
const matches = text.match(/".*?"/g); // Matches text inside double quotes, non-greedily
|
||||||
text = matches ? matches.join(' ... ... ... ') : text;
|
const partJoiner = (ttsProvider?.separator || ' ... ');
|
||||||
|
text = matches ? matches.join(partJoiner) : text;
|
||||||
}
|
}
|
||||||
console.log(`TTS: ${text}`)
|
console.log(`TTS: ${text}`)
|
||||||
const char = currentTtsJob.name
|
const char = currentTtsJob.name
|
||||||
@ -295,6 +334,7 @@ function loadSettings() {
|
|||||||
)
|
)
|
||||||
$('#tts_narrate_dialogues').prop('checked', extension_settings.tts.narrate_dialogues_only)
|
$('#tts_narrate_dialogues').prop('checked', extension_settings.tts.narrate_dialogues_only)
|
||||||
$('#tts_narrate_quoted').prop('checked', extension_settings.tts.narrate_quoted_only)
|
$('#tts_narrate_quoted').prop('checked', extension_settings.tts.narrate_quoted_only)
|
||||||
|
$('body').toggleClass('tts', extension_settings.tts.enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSettings = {
|
const defaultSettings = {
|
||||||
@ -506,10 +546,11 @@ $(document).ready(function () {
|
|||||||
$('#tts_provider').append($("<option />").val(provider).text(provider))
|
$('#tts_provider').append($("<option />").val(provider).text(provider))
|
||||||
}
|
}
|
||||||
$('#tts_provider').on('change', onTtsProviderChange)
|
$('#tts_provider').on('change', onTtsProviderChange)
|
||||||
|
$(document).on('click', '.mes_narrate', onNarrateOneMessage);
|
||||||
}
|
}
|
||||||
addExtensionControls() // No init dependencies
|
addExtensionControls() // No init dependencies
|
||||||
loadSettings() // Depends on Extension Controls and loadTtsProvider
|
loadSettings() // Depends on Extension Controls and loadTtsProvider
|
||||||
loadTtsProvider(extension_settings.tts.currentProvider) // No dependencies
|
loadTtsProvider(extension_settings.tts.currentProvider) // No dependencies
|
||||||
addAudioControl() // Depends on Extension Controls
|
addAudioControl() // Depends on Extension Controls
|
||||||
setInterval(moduleWorker, UPDATE_INTERVAL) // Init depends on all the things
|
setInterval(moduleWorkerWrapper, UPDATE_INTERVAL) // Init depends on all the things
|
||||||
})
|
})
|
||||||
|
@ -9,6 +9,7 @@ class SileroTtsProvider {
|
|||||||
|
|
||||||
settings
|
settings
|
||||||
voices = []
|
voices = []
|
||||||
|
separator = ' .. '
|
||||||
|
|
||||||
defaultSettings = {
|
defaultSettings = {
|
||||||
provider_endpoint: "http://localhost:8001/tts",
|
provider_endpoint: "http://localhost:8001/tts",
|
||||||
|
@ -21,6 +21,7 @@ class SystemTtsProvider {
|
|||||||
fallbackPreview = 'Neque porro quisquam est qui dolorem ipsum quia dolor sit amet'
|
fallbackPreview = 'Neque porro quisquam est qui dolorem ipsum quia dolor sit amet'
|
||||||
settings
|
settings
|
||||||
voices = []
|
voices = []
|
||||||
|
separator = ' ... '
|
||||||
|
|
||||||
defaultSettings = {
|
defaultSettings = {
|
||||||
voiceMap: {},
|
voiceMap: {},
|
||||||
|
@ -101,6 +101,7 @@ const default_settings = {
|
|||||||
openai_model: 'gpt-3.5-turbo',
|
openai_model: 'gpt-3.5-turbo',
|
||||||
jailbreak_system: false,
|
jailbreak_system: false,
|
||||||
reverse_proxy: '',
|
reverse_proxy: '',
|
||||||
|
oai_breakdown: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const oai_settings = {
|
const oai_settings = {
|
||||||
@ -125,6 +126,7 @@ const oai_settings = {
|
|||||||
openai_model: 'gpt-3.5-turbo',
|
openai_model: 'gpt-3.5-turbo',
|
||||||
jailbreak_system: false,
|
jailbreak_system: false,
|
||||||
reverse_proxy: '',
|
reverse_proxy: '',
|
||||||
|
oai_breakdown: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let openai_setting_names;
|
let openai_setting_names;
|
||||||
@ -205,22 +207,10 @@ function setOpenAIMessageExamples(mesExamplesArray) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateOpenAIPromptCache(charPersonality, topAnchorDepth, anchorTop, bottomAnchorThreshold, anchorBottom) {
|
function generateOpenAIPromptCache() {
|
||||||
openai_msgs = openai_msgs.reverse();
|
openai_msgs = openai_msgs.reverse();
|
||||||
openai_msgs.forEach(function (msg, i, arr) {//For added anchors and others
|
openai_msgs.forEach(function (msg, i, arr) {
|
||||||
let item = msg["content"];
|
let item = msg["content"];
|
||||||
if (i === openai_msgs.length - topAnchorDepth) {
|
|
||||||
let personalityAndAnchor = [charPersonality, anchorTop].filter(x => x).join(' ');
|
|
||||||
if (personalityAndAnchor) {
|
|
||||||
item = `[${name2} is ${personalityAndAnchor}]\n${item}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i === openai_msgs.length - 1 && openai_msgs.length > bottomAnchorThreshold && msg.role === "user") {//For add anchor in end
|
|
||||||
if (anchorBottom) {
|
|
||||||
item = anchorBottom + "\n" + item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
msg["content"] = item;
|
msg["content"] = item;
|
||||||
openai_msgs[i] = msg;
|
openai_msgs[i] = msg;
|
||||||
});
|
});
|
||||||
@ -310,23 +300,25 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
|
|||||||
let whole_prompt = getSystemPrompt(nsfw_toggle_prompt, enhance_definitions_prompt, wiBefore, storyString, wiAfter, extensionPrompt, isImpersonate);
|
let whole_prompt = getSystemPrompt(nsfw_toggle_prompt, enhance_definitions_prompt, wiBefore, storyString, wiAfter, extensionPrompt, isImpersonate);
|
||||||
|
|
||||||
// Join by a space and replace placeholders with real user/char names
|
// Join by a space and replace placeholders with real user/char names
|
||||||
storyString = substituteParams(whole_prompt.join(" ")).replace(/\r/gm, '').trim();
|
storyString = substituteParams(whole_prompt.join("\n")).replace(/\r/gm, '').trim();
|
||||||
|
|
||||||
let prompt_msg = { "role": "system", "content": storyString }
|
let prompt_msg = { "role": "system", "content": storyString }
|
||||||
let examples_tosend = [];
|
let examples_tosend = [];
|
||||||
let openai_msgs_tosend = [];
|
let openai_msgs_tosend = [];
|
||||||
|
|
||||||
// todo: static value, maybe include in the initial context calculation
|
// todo: static value, maybe include in the initial context calculation
|
||||||
|
const handler_instance = new TokenHandler(countTokens);
|
||||||
|
|
||||||
let new_chat_msg = { "role": "system", "content": "[Start a new chat]" };
|
let new_chat_msg = { "role": "system", "content": "[Start a new chat]" };
|
||||||
let start_chat_count = countTokens([new_chat_msg], true);
|
let start_chat_count = handler_instance.count([new_chat_msg], true, 'start_chat');
|
||||||
await delay(1);
|
await delay(1);
|
||||||
let total_count = countTokens([prompt_msg], true) + start_chat_count;
|
let total_count = handler_instance.count([prompt_msg], true, 'prompt') + start_chat_count;
|
||||||
await delay(1);
|
await delay(1);
|
||||||
|
|
||||||
if (bias && bias.trim().length) {
|
if (bias && bias.trim().length) {
|
||||||
let bias_msg = { "role": "system", "content": bias.trim() };
|
let bias_msg = { "role": "system", "content": bias.trim() };
|
||||||
openai_msgs.push(bias_msg);
|
openai_msgs.push(bias_msg);
|
||||||
total_count += countTokens([bias_msg], true);
|
total_count += handler_instance.count([bias_msg], true, 'bias');
|
||||||
await delay(1);
|
await delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,13 +335,14 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
|
|||||||
openai_msgs.push(group_nudge);
|
openai_msgs.push(group_nudge);
|
||||||
|
|
||||||
// add a group nudge count
|
// add a group nudge count
|
||||||
let group_nudge_count = countTokens([group_nudge], true);
|
let group_nudge_count = handler_instance.count([group_nudge], true, 'nudge');
|
||||||
await delay(1);
|
await delay(1);
|
||||||
total_count += group_nudge_count;
|
total_count += group_nudge_count;
|
||||||
|
|
||||||
// recount tokens for new start message
|
// recount tokens for new start message
|
||||||
total_count -= start_chat_count
|
total_count -= start_chat_count
|
||||||
start_chat_count = countTokens([new_chat_msg], true);
|
handler_instance.uncount(start_chat_count, 'start_chat');
|
||||||
|
start_chat_count = handler_instance.count([new_chat_msg], true);
|
||||||
await delay(1);
|
await delay(1);
|
||||||
total_count += start_chat_count;
|
total_count += start_chat_count;
|
||||||
}
|
}
|
||||||
@ -358,7 +351,7 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
|
|||||||
const jailbreakMessage = { "role": "system", "content": substituteParams(oai_settings.jailbreak_prompt) };
|
const jailbreakMessage = { "role": "system", "content": substituteParams(oai_settings.jailbreak_prompt) };
|
||||||
openai_msgs.push(jailbreakMessage);
|
openai_msgs.push(jailbreakMessage);
|
||||||
|
|
||||||
total_count += countTokens([jailbreakMessage], true);
|
total_count += handler_instance.count([jailbreakMessage], true, 'jailbreak');
|
||||||
await delay(1);
|
await delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,7 +359,7 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
|
|||||||
const impersonateMessage = { "role": "system", "content": substituteParams(oai_settings.impersonation_prompt) };
|
const impersonateMessage = { "role": "system", "content": substituteParams(oai_settings.impersonation_prompt) };
|
||||||
openai_msgs.push(impersonateMessage);
|
openai_msgs.push(impersonateMessage);
|
||||||
|
|
||||||
total_count += countTokens([impersonateMessage], true);
|
total_count += handler_instance.count([impersonateMessage], true, 'impersonate');
|
||||||
await delay(1);
|
await delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,12 +382,12 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
|
|||||||
examples_tosend.push(example);
|
examples_tosend.push(example);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
total_count += countTokens(examples_tosend, true);
|
total_count += handler_instance.count(examples_tosend, true, 'examples');
|
||||||
await delay(1);
|
await delay(1);
|
||||||
// go from newest message to oldest, because we want to delete the older ones from the context
|
// go from newest message to oldest, because we want to delete the older ones from the context
|
||||||
for (let j = openai_msgs.length - 1; j >= 0; j--) {
|
for (let j = openai_msgs.length - 1; j >= 0; j--) {
|
||||||
let item = openai_msgs[j];
|
let item = openai_msgs[j];
|
||||||
let item_count = countTokens(item, true);
|
let item_count = handler_instance.count(item, true, 'conversation');
|
||||||
await delay(1);
|
await delay(1);
|
||||||
// If we have enough space for this message, also account for the max assistant reply size
|
// If we have enough space for this message, also account for the max assistant reply size
|
||||||
if ((total_count + item_count) < (this_max_context - oai_settings.openai_max_tokens)) {
|
if ((total_count + item_count) < (this_max_context - oai_settings.openai_max_tokens)) {
|
||||||
@ -403,13 +396,14 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// early break since if we still have more messages, they just won't fit anyway
|
// early break since if we still have more messages, they just won't fit anyway
|
||||||
|
handler_instance.uncount(item_count, 'conversation');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let j = openai_msgs.length - 1; j >= 0; j--) {
|
for (let j = openai_msgs.length - 1; j >= 0; j--) {
|
||||||
let item = openai_msgs[j];
|
let item = openai_msgs[j];
|
||||||
let item_count = countTokens(item, true);
|
let item_count = handler_instance.count(item, true, 'conversation');
|
||||||
await delay(1);
|
await delay(1);
|
||||||
// If we have enough space for this message, also account for the max assistant reply size
|
// If we have enough space for this message, also account for the max assistant reply size
|
||||||
if ((total_count + item_count) < (this_max_context - oai_settings.openai_max_tokens)) {
|
if ((total_count + item_count) < (this_max_context - oai_settings.openai_max_tokens)) {
|
||||||
@ -418,11 +412,12 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// early break since if we still have more messages, they just won't fit anyway
|
// early break since if we still have more messages, they just won't fit anyway
|
||||||
|
handler_instance.uncount(item_count, 'conversation');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(total_count);
|
//console.log(total_count);
|
||||||
|
|
||||||
// each example block contains multiple user/bot messages
|
// each example block contains multiple user/bot messages
|
||||||
for (let example_block of openai_msgs_example) {
|
for (let example_block of openai_msgs_example) {
|
||||||
@ -432,7 +427,7 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
|
|||||||
example_block = [new_chat_msg, ...example_block];
|
example_block = [new_chat_msg, ...example_block];
|
||||||
|
|
||||||
// add the block only if there is enough space for all its messages
|
// add the block only if there is enough space for all its messages
|
||||||
const example_count = countTokens(example_block, true);
|
const example_count = handler_instance.count(example_block, true, 'examples');
|
||||||
await delay(1);
|
await delay(1);
|
||||||
if ((total_count + example_count) < (this_max_context - oai_settings.openai_max_tokens)) {
|
if ((total_count + example_count) < (this_max_context - oai_settings.openai_max_tokens)) {
|
||||||
examples_tosend.push(...example_block)
|
examples_tosend.push(...example_block)
|
||||||
@ -440,6 +435,7 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// early break since more examples probably won't fit anyway
|
// early break since more examples probably won't fit anyway
|
||||||
|
handler_instance.uncount(example_count, 'examples');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,10 +447,14 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
|
|||||||
openai_msgs_tosend.reverse();
|
openai_msgs_tosend.reverse();
|
||||||
openai_msgs_tosend = [prompt_msg, ...examples_tosend, new_chat_msg, ...openai_msgs_tosend]
|
openai_msgs_tosend = [prompt_msg, ...examples_tosend, new_chat_msg, ...openai_msgs_tosend]
|
||||||
|
|
||||||
console.log("We're sending this:")
|
//console.log("We're sending this:")
|
||||||
console.log(openai_msgs_tosend);
|
//console.log(openai_msgs_tosend);
|
||||||
console.log(`Calculated the total context to be ${total_count} tokens`);
|
//console.log(`Calculated the total context to be ${total_count} tokens`);
|
||||||
return openai_msgs_tosend;
|
handler_instance.log();
|
||||||
|
return [
|
||||||
|
openai_msgs_tosend,
|
||||||
|
oai_settings.oai_breakdown ? handler_instance.counts : false,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSystemPrompt(nsfw_toggle_prompt, enhance_definitions_prompt, wiBefore, storyString, wiAfter, extensionPrompt, isImpersonate) {
|
function getSystemPrompt(nsfw_toggle_prompt, enhance_definitions_prompt, wiBefore, storyString, wiAfter, extensionPrompt, isImpersonate) {
|
||||||
@ -469,7 +469,7 @@ function getSystemPrompt(nsfw_toggle_prompt, enhance_definitions_prompt, wiBefor
|
|||||||
whole_prompt = [nsfw_toggle_prompt, oai_settings.main_prompt, enhance_definitions_prompt + "\n\n" + wiBefore, storyString, wiAfter, extensionPrompt];
|
whole_prompt = [nsfw_toggle_prompt, oai_settings.main_prompt, enhance_definitions_prompt + "\n\n" + wiBefore, storyString, wiAfter, extensionPrompt];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
whole_prompt = [oai_settings.main_prompt, nsfw_toggle_prompt, enhance_definitions_prompt + "\n\n" + wiBefore, storyString, wiAfter, extensionPrompt];
|
whole_prompt = [oai_settings.main_prompt, nsfw_toggle_prompt, enhance_definitions_prompt, "\n", wiBefore, storyString, wiAfter, extensionPrompt].filter(elem => elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return whole_prompt;
|
return whole_prompt;
|
||||||
@ -616,6 +616,39 @@ async function calculateLogitBias() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TokenHandler {
|
||||||
|
constructor(countTokenFn) {
|
||||||
|
this.countTokenFn = countTokenFn;
|
||||||
|
this.counts = {
|
||||||
|
'start_chat': 0,
|
||||||
|
'prompt': 0,
|
||||||
|
'bias': 0,
|
||||||
|
'nudge': 0,
|
||||||
|
'jailbreak': 0,
|
||||||
|
'impersonate': 0,
|
||||||
|
'examples': 0,
|
||||||
|
'conversation': 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
uncount(value, type) {
|
||||||
|
this.counts[type] -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
count(messages, full, type) {
|
||||||
|
//console.log(messages);
|
||||||
|
const token_count = this.countTokenFn(messages, full);
|
||||||
|
this.counts[type] += token_count;
|
||||||
|
|
||||||
|
return token_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
const total = Object.values(this.counts).reduce((a, b) => a + b);
|
||||||
|
console.table({ ...this.counts, 'total': total });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function countTokens(messages, full = false) {
|
function countTokens(messages, full = false) {
|
||||||
let chatId = 'undefined';
|
let chatId = 'undefined';
|
||||||
|
|
||||||
@ -705,6 +738,7 @@ function loadOpenAISettings(data, settings) {
|
|||||||
if (settings.nsfw_first !== undefined) oai_settings.nsfw_first = !!settings.nsfw_first;
|
if (settings.nsfw_first !== undefined) oai_settings.nsfw_first = !!settings.nsfw_first;
|
||||||
if (settings.openai_model !== undefined) oai_settings.openai_model = settings.openai_model;
|
if (settings.openai_model !== undefined) oai_settings.openai_model = settings.openai_model;
|
||||||
if (settings.jailbreak_system !== undefined) oai_settings.jailbreak_system = !!settings.jailbreak_system;
|
if (settings.jailbreak_system !== undefined) oai_settings.jailbreak_system = !!settings.jailbreak_system;
|
||||||
|
if (settings.oai_breakdown !== undefined) oai_settings.oai_breakdown = !!settings.oai_breakdown;
|
||||||
|
|
||||||
$('#stream_toggle').prop('checked', oai_settings.stream_openai);
|
$('#stream_toggle').prop('checked', oai_settings.stream_openai);
|
||||||
|
|
||||||
@ -720,6 +754,7 @@ function loadOpenAISettings(data, settings) {
|
|||||||
$('#wrap_in_quotes').prop('checked', oai_settings.wrap_in_quotes);
|
$('#wrap_in_quotes').prop('checked', oai_settings.wrap_in_quotes);
|
||||||
$('#nsfw_first').prop('checked', oai_settings.nsfw_first);
|
$('#nsfw_first').prop('checked', oai_settings.nsfw_first);
|
||||||
$('#jailbreak_system').prop('checked', oai_settings.jailbreak_system);
|
$('#jailbreak_system').prop('checked', oai_settings.jailbreak_system);
|
||||||
|
$('#oai_breakdown').prop('checked', oai_settings.oai_breakdown);
|
||||||
|
|
||||||
if (settings.main_prompt !== undefined) oai_settings.main_prompt = settings.main_prompt;
|
if (settings.main_prompt !== undefined) oai_settings.main_prompt = settings.main_prompt;
|
||||||
if (settings.nsfw_prompt !== undefined) oai_settings.nsfw_prompt = settings.nsfw_prompt;
|
if (settings.nsfw_prompt !== undefined) oai_settings.nsfw_prompt = settings.nsfw_prompt;
|
||||||
@ -839,6 +874,7 @@ async function saveOpenAIPreset(name, settings) {
|
|||||||
jailbreak_system: settings.jailbreak_system,
|
jailbreak_system: settings.jailbreak_system,
|
||||||
impersonation_prompt: settings.impersonation_prompt,
|
impersonation_prompt: settings.impersonation_prompt,
|
||||||
bias_preset_selected: settings.bias_preset_selected,
|
bias_preset_selected: settings.bias_preset_selected,
|
||||||
|
oai_breakdown: settings.oai_breakdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
const savePresetSettings = await fetch(`/savepreset_openai?name=${name}`, {
|
const savePresetSettings = await fetch(`/savepreset_openai?name=${name}`, {
|
||||||
@ -1046,7 +1082,7 @@ async function onDeletePresetClick() {
|
|||||||
const response = await fetch('/deletepreset_openai', {
|
const response = await fetch('/deletepreset_openai', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getRequestHeaders(),
|
headers: getRequestHeaders(),
|
||||||
body: JSON.stringify({name: nameToDelete}),
|
body: JSON.stringify({ name: nameToDelete }),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@ -1097,6 +1133,7 @@ function onSettingsPresetChange() {
|
|||||||
wrap_in_quotes: ['#wrap_in_quotes', 'wrap_in_quotes', true],
|
wrap_in_quotes: ['#wrap_in_quotes', 'wrap_in_quotes', true],
|
||||||
nsfw_first: ['#nsfw_first', 'nsfw_first', true],
|
nsfw_first: ['#nsfw_first', 'nsfw_first', true],
|
||||||
jailbreak_system: ['#jailbreak_system', 'jailbreak_system', true],
|
jailbreak_system: ['#jailbreak_system', 'jailbreak_system', true],
|
||||||
|
oai_breakdown: ['#oai_breakdown', 'oai_breakdown', true],
|
||||||
main_prompt: ['#main_prompt_textarea', 'main_prompt', false],
|
main_prompt: ['#main_prompt_textarea', 'main_prompt', false],
|
||||||
nsfw_prompt: ['#nsfw_prompt_textarea', 'nsfw_prompt', false],
|
nsfw_prompt: ['#nsfw_prompt_textarea', 'nsfw_prompt', false],
|
||||||
jailbreak_prompt: ['#jailbreak_prompt_textarea', 'jailbreak_prompt', false],
|
jailbreak_prompt: ['#jailbreak_prompt_textarea', 'jailbreak_prompt', false],
|
||||||
@ -1269,6 +1306,16 @@ $(document).ready(function () {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#oai_breakdown").on('change', function () {
|
||||||
|
oai_settings.oai_breakdown = !!$(this).prop("checked");
|
||||||
|
if (!oai_settings.oai_breakdown) {
|
||||||
|
$("#token_breakdown").css('display', 'none');
|
||||||
|
} else {
|
||||||
|
$("#token_breakdown").css('display', 'flex');
|
||||||
|
}
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
|
||||||
// auto-select a preset based on character/group name
|
// auto-select a preset based on character/group name
|
||||||
$(document).on("click", ".character_select", function () {
|
$(document).on("click", ".character_select", function () {
|
||||||
const chid = $(this).attr('chid');
|
const chid = $(this).attr('chid');
|
||||||
@ -1322,18 +1369,18 @@ $(document).ready(function () {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#api_button_openai").on('click', onConnectButtonClick);
|
$("#api_button_openai").on("click", onConnectButtonClick);
|
||||||
$("#openai_reverse_proxy").on('input', onReverseProxyInput);
|
$("#openai_reverse_proxy").on("input", onReverseProxyInput);
|
||||||
$("#model_openai_select").on('change', onModelChange);
|
$("#model_openai_select").on("change", onModelChange);
|
||||||
$("#settings_perset_openai").on('change', onSettingsPresetChange);
|
$("#settings_perset_openai").on("change", onSettingsPresetChange);
|
||||||
$("#new_oai_preset").on('click', onNewPresetClick);
|
$("#new_oai_preset").on("click", onNewPresetClick);
|
||||||
$("#delete_oai_preset").on('click', onDeletePresetClick);
|
$("#delete_oai_preset").on("click", onDeletePresetClick);
|
||||||
$("#openai_api_usage").on('click', showApiKeyUsage);
|
$("#openai_api_usage").on("click", showApiKeyUsage);
|
||||||
$('#openai_logit_bias_preset').on('change', onLogitBiasPresetChange);
|
$("#openai_logit_bias_preset").on("change", onLogitBiasPresetChange);
|
||||||
$('#openai_logit_bias_new_preset').on('click', createNewLogitBiasPreset);
|
$("#openai_logit_bias_new_preset").on("click", createNewLogitBiasPreset);
|
||||||
$('#openai_logit_bias_new_entry').on('click', createNewLogitBiasEntry);
|
$("#openai_logit_bias_new_entry").on("click", createNewLogitBiasEntry);
|
||||||
$('#openai_logit_bias_import_file').on('input', onLogitBiasPresetImportFileChange);
|
$("#openai_logit_bias_import_file").on("input", onLogitBiasPresetImportFileChange);
|
||||||
$('#openai_logit_bias_import_preset').on('click', onLogitBiasPresetImportClick);
|
$("#openai_logit_bias_import_preset").on("click", onLogitBiasPresetImportClick);
|
||||||
$('#openai_logit_bias_export_preset').on('click', onLogitBiasPresetExportClick);
|
$("#openai_logit_bias_export_preset").on("click", onLogitBiasPresetExportClick);
|
||||||
$('#openai_logit_bias_delete_preset').on('click', onLogitBiasPresetDeleteClick);
|
$("#openai_logit_bias_delete_preset").on("click", onLogitBiasPresetDeleteClick);
|
||||||
});
|
});
|
||||||
|
@ -76,6 +76,8 @@ let power_user = {
|
|||||||
disable_personality_formatting: false,
|
disable_personality_formatting: false,
|
||||||
disable_examples_formatting: false,
|
disable_examples_formatting: false,
|
||||||
disable_start_formatting: false,
|
disable_start_formatting: false,
|
||||||
|
trim_sentences: false,
|
||||||
|
include_newline: false,
|
||||||
always_force_name2: false,
|
always_force_name2: false,
|
||||||
multigen: false,
|
multigen: false,
|
||||||
multigen_first_chunk: 50,
|
multigen_first_chunk: 50,
|
||||||
@ -107,9 +109,14 @@ let power_user = {
|
|||||||
noShadows: false,
|
noShadows: false,
|
||||||
theme: 'Default (Dark)',
|
theme: 'Default (Dark)',
|
||||||
|
|
||||||
|
auto_swipe: false,
|
||||||
|
auto_swipe_minimum_length: 0,
|
||||||
|
auto_swipe_blacklist: [],
|
||||||
|
auto_swipe_blacklist_threshold: 2,
|
||||||
auto_scroll_chat_to_bottom: true,
|
auto_scroll_chat_to_bottom: true,
|
||||||
auto_fix_generated_markdown: true,
|
auto_fix_generated_markdown: true,
|
||||||
send_on_enter: send_on_enter_options.AUTO,
|
send_on_enter: send_on_enter_options.AUTO,
|
||||||
|
console_log_prompts: false,
|
||||||
render_formulas: false,
|
render_formulas: false,
|
||||||
allow_name1_display: false,
|
allow_name1_display: false,
|
||||||
allow_name2_display: false,
|
allow_name2_display: false,
|
||||||
@ -477,6 +484,12 @@ function loadPowerUserSettings(settings, data) {
|
|||||||
power_user.font_scale = Number(localStorage.getItem(storage_keys.font_scale) ?? 1);
|
power_user.font_scale = Number(localStorage.getItem(storage_keys.font_scale) ?? 1);
|
||||||
power_user.blur_strength = Number(localStorage.getItem(storage_keys.blur_strength) ?? 10);
|
power_user.blur_strength = Number(localStorage.getItem(storage_keys.blur_strength) ?? 10);
|
||||||
|
|
||||||
|
$('#auto_swipe').prop("checked", power_user.auto_swipe);
|
||||||
|
$('#auto_swipe_minimum_length').val(power_user.auto_swipe_minimum_length);
|
||||||
|
$('#auto_swipe_blacklist').val(power_user.auto_swipe_blacklist.join(", "));
|
||||||
|
$('#auto_swipe_blacklist_threshold').val(power_user.auto_swipe_blacklist_threshold);
|
||||||
|
|
||||||
|
$("#console_log_prompts").prop("checked", power_user.console_log_prompts);
|
||||||
$('#auto_fix_generated_markdown').prop("checked", power_user.auto_fix_generated_markdown);
|
$('#auto_fix_generated_markdown').prop("checked", power_user.auto_fix_generated_markdown);
|
||||||
$('#auto_scroll_chat_to_bottom').prop("checked", power_user.auto_scroll_chat_to_bottom);
|
$('#auto_scroll_chat_to_bottom').prop("checked", power_user.auto_scroll_chat_to_bottom);
|
||||||
$(`#tokenizer option[value="${power_user.tokenizer}"]`).attr('selected', true);
|
$(`#tokenizer option[value="${power_user.tokenizer}"]`).attr('selected', true);
|
||||||
@ -490,6 +503,8 @@ function loadPowerUserSettings(settings, data) {
|
|||||||
$("#always-force-name2-checkbox").prop("checked", power_user.always_force_name2);
|
$("#always-force-name2-checkbox").prop("checked", power_user.always_force_name2);
|
||||||
$("#disable-examples-formatting-checkbox").prop("checked", power_user.disable_examples_formatting);
|
$("#disable-examples-formatting-checkbox").prop("checked", power_user.disable_examples_formatting);
|
||||||
$('#disable-start-formatting-checkbox').prop("checked", power_user.disable_start_formatting);
|
$('#disable-start-formatting-checkbox').prop("checked", power_user.disable_start_formatting);
|
||||||
|
$("#trim_sentences_checkbox").prop("checked", power_user.trim_sentences);
|
||||||
|
$("#include_newline_checkbox").prop("checked", power_user.include_newline);
|
||||||
$('#render_formulas').prop("checked", power_user.render_formulas);
|
$('#render_formulas').prop("checked", power_user.render_formulas);
|
||||||
$("#custom_chat_separator").val(power_user.custom_chat_separator);
|
$("#custom_chat_separator").val(power_user.custom_chat_separator);
|
||||||
$("#fast_ui_mode").prop("checked", power_user.fast_ui_mode);
|
$("#fast_ui_mode").prop("checked", power_user.fast_ui_mode);
|
||||||
@ -544,7 +559,7 @@ function loadPowerUserSettings(settings, data) {
|
|||||||
|
|
||||||
function loadMaxContextUnlocked() {
|
function loadMaxContextUnlocked() {
|
||||||
$('#max_context_unlocked').prop('checked', power_user.max_context_unlocked);
|
$('#max_context_unlocked').prop('checked', power_user.max_context_unlocked);
|
||||||
$('#max_context_unlocked').on('change', function() {
|
$('#max_context_unlocked').on('change', function () {
|
||||||
power_user.max_context_unlocked = !!$(this).prop('checked');
|
power_user.max_context_unlocked = !!$(this).prop('checked');
|
||||||
switchMaxContextSize();
|
switchMaxContextSize();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
@ -770,18 +785,21 @@ function resetMovablePanels() {
|
|||||||
document.getElementById("sheld").style.right = '';
|
document.getElementById("sheld").style.right = '';
|
||||||
document.getElementById("sheld").style.height = '';
|
document.getElementById("sheld").style.height = '';
|
||||||
document.getElementById("sheld").style.width = '';
|
document.getElementById("sheld").style.width = '';
|
||||||
|
document.getElementById("sheld").style.margin = '';
|
||||||
|
|
||||||
|
|
||||||
document.getElementById("left-nav-panel").style.top = '';
|
document.getElementById("left-nav-panel").style.top = '';
|
||||||
document.getElementById("left-nav-panel").style.left = '';
|
document.getElementById("left-nav-panel").style.left = '';
|
||||||
document.getElementById("left-nav-panel").style.height = '';
|
document.getElementById("left-nav-panel").style.height = '';
|
||||||
document.getElementById("left-nav-panel").style.width = '';
|
document.getElementById("left-nav-panel").style.width = '';
|
||||||
|
document.getElementById("left-nav-panel").style.margin = '';
|
||||||
|
|
||||||
document.getElementById("right-nav-panel").style.top = '';
|
document.getElementById("right-nav-panel").style.top = '';
|
||||||
document.getElementById("right-nav-panel").style.left = '';
|
document.getElementById("right-nav-panel").style.left = '';
|
||||||
document.getElementById("right-nav-panel").style.right = '';
|
document.getElementById("right-nav-panel").style.right = '';
|
||||||
document.getElementById("right-nav-panel").style.height = '';
|
document.getElementById("right-nav-panel").style.height = '';
|
||||||
document.getElementById("right-nav-panel").style.width = '';
|
document.getElementById("right-nav-panel").style.width = '';
|
||||||
|
document.getElementById("right-nav-panel").style.margin = '';
|
||||||
|
|
||||||
document.getElementById("expression-holder").style.top = '';
|
document.getElementById("expression-holder").style.top = '';
|
||||||
document.getElementById("expression-holder").style.left = '';
|
document.getElementById("expression-holder").style.left = '';
|
||||||
@ -789,6 +807,7 @@ function resetMovablePanels() {
|
|||||||
document.getElementById("expression-holder").style.bottom = '';
|
document.getElementById("expression-holder").style.bottom = '';
|
||||||
document.getElementById("expression-holder").style.height = '';
|
document.getElementById("expression-holder").style.height = '';
|
||||||
document.getElementById("expression-holder").style.width = '';
|
document.getElementById("expression-holder").style.width = '';
|
||||||
|
document.getElementById("expression-holder").style.margin = '';
|
||||||
|
|
||||||
document.getElementById("avatar_zoom_popup").style.top = '';
|
document.getElementById("avatar_zoom_popup").style.top = '';
|
||||||
document.getElementById("avatar_zoom_popup").style.left = '';
|
document.getElementById("avatar_zoom_popup").style.left = '';
|
||||||
@ -796,6 +815,15 @@ function resetMovablePanels() {
|
|||||||
document.getElementById("avatar_zoom_popup").style.bottom = '';
|
document.getElementById("avatar_zoom_popup").style.bottom = '';
|
||||||
document.getElementById("avatar_zoom_popup").style.height = '';
|
document.getElementById("avatar_zoom_popup").style.height = '';
|
||||||
document.getElementById("avatar_zoom_popup").style.width = '';
|
document.getElementById("avatar_zoom_popup").style.width = '';
|
||||||
|
document.getElementById("avatar_zoom_popup").style.margin = '';
|
||||||
|
|
||||||
|
document.getElementById("WorldInfo").style.top = '';
|
||||||
|
document.getElementById("WorldInfo").style.left = '';
|
||||||
|
document.getElementById("WorldInfo").style.right = '';
|
||||||
|
document.getElementById("WorldInfo").style.bottom = '';
|
||||||
|
document.getElementById("WorldInfo").style.height = '';
|
||||||
|
document.getElementById("WorldInfo").style.width = '';
|
||||||
|
document.getElementById("WorldInfo").style.margin = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
@ -841,6 +869,27 @@ $(document).ready(() => {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// include newline is the child of trim sentences
|
||||||
|
// if include newline is checked, trim sentences must be checked
|
||||||
|
// if trim sentences is unchecked, include newline must be unchecked
|
||||||
|
$("#trim_sentences_checkbox").change(function() {
|
||||||
|
power_user.trim_sentences = !!$(this).prop("checked");
|
||||||
|
if (!$(this).prop("checked")) {
|
||||||
|
$("#include_newline_checkbox").prop("checked", false);
|
||||||
|
power_user.include_newline = false;
|
||||||
|
}
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#include_newline_checkbox").change(function() {
|
||||||
|
power_user.include_newline = !!$(this).prop("checked");
|
||||||
|
if ($(this).prop("checked")) {
|
||||||
|
$("#trim_sentences_checkbox").prop("checked", true);
|
||||||
|
power_user.trim_sentences = true;
|
||||||
|
}
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
|
||||||
$("#always-force-name2-checkbox").change(function () {
|
$("#always-force-name2-checkbox").change(function () {
|
||||||
power_user.always_force_name2 = !!$(this).prop("checked");
|
power_user.always_force_name2 = !!$(this).prop("checked");
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
@ -1002,12 +1051,47 @@ $(document).ready(() => {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#auto_swipe').on('input', function () {
|
||||||
|
power_user.auto_swipe = !!$(this).prop('checked');
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#auto_swipe_blacklist').on('input', function () {
|
||||||
|
power_user.auto_swipe_blacklist = $(this).val()
|
||||||
|
.split(",")
|
||||||
|
.map(str => str.trim())
|
||||||
|
.filter(str => str);
|
||||||
|
console.log("power_user.auto_swipe_blacklist", power_user.auto_swipe_blacklist)
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#auto_swipe_minimum_length').on('input', function () {
|
||||||
|
const number = parseInt($(this).val());
|
||||||
|
if (!isNaN(number)) {
|
||||||
|
power_user.auto_swipe_minimum_length = number;
|
||||||
|
saveSettingsDebounced();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#auto_swipe_blacklist_threshold').on('input', function () {
|
||||||
|
const number = parseInt($(this).val());
|
||||||
|
if (!isNaN(number)) {
|
||||||
|
power_user.auto_swipe_blacklist_threshold = number;
|
||||||
|
saveSettingsDebounced();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('#auto_fix_generated_markdown').on('input', function () {
|
$('#auto_fix_generated_markdown').on('input', function () {
|
||||||
power_user.auto_fix_generated_markdown = !!$(this).prop('checked');
|
power_user.auto_fix_generated_markdown = !!$(this).prop('checked');
|
||||||
reloadCurrentChat();
|
reloadCurrentChat();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#console_log_prompts").on('input', function () {
|
||||||
|
power_user.console_log_prompts = !!$(this).prop('checked');
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
|
||||||
$('#auto_scroll_chat_to_bottom').on("input", function () {
|
$('#auto_scroll_chat_to_bottom').on("input", function () {
|
||||||
power_user.auto_scroll_chat_to_bottom = !!$(this).prop('checked');
|
power_user.auto_scroll_chat_to_bottom = !!$(this).prop('checked');
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
@ -97,7 +97,9 @@ function executeSlashCommands(text) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lines = text.split('\n');
|
// Hack to allow multi-line slash commands
|
||||||
|
// All slash command messages should begin with a slash
|
||||||
|
const lines = [text];
|
||||||
const linesToRemove = [];
|
const linesToRemove = [];
|
||||||
|
|
||||||
let interrupt = false;
|
let interrupt = false;
|
||||||
|
303
public/scripts/uniqolor.js
Normal file
303
public/scripts/uniqolor.js
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
const SATURATION_BOUND = [0, 100];
|
||||||
|
const LIGHTNESS_BOUND = [0, 100];
|
||||||
|
|
||||||
|
const pad2 = str => `${str.length === 1 ? '0' : ''}${str}`;
|
||||||
|
|
||||||
|
const clamp = (num, min, max) => Math.max(Math.min(num, max), min);
|
||||||
|
|
||||||
|
const random = (min, max) => Math.floor(Math.random() * ((max - min) + 1)) + min;
|
||||||
|
|
||||||
|
const randomExclude = (min, max, exclude) => {
|
||||||
|
const r = random(min, max);
|
||||||
|
|
||||||
|
for (let i = 0; i < exclude?.length; i++) {
|
||||||
|
const value = exclude[i];
|
||||||
|
|
||||||
|
if (value?.length === 2 && r >= value[0] && r <= value[1]) {
|
||||||
|
return randomExclude(min, max, exclude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate hashCode
|
||||||
|
* @param {string} str
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
const hashCode = str => {
|
||||||
|
const len = str.length;
|
||||||
|
let hash = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
hash = ((hash << 5) - hash) + str.charCodeAt(i);
|
||||||
|
hash &= hash; // Convert to 32bit integer
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clamps `num` within the inclusive `range` bounds
|
||||||
|
* @param {number} num
|
||||||
|
* @param {number|Array} range
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
const boundHashCode = (num, range) => {
|
||||||
|
if (typeof range === 'number') {
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (num % Math.abs(range[1] - range[0])) + range[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitizing the `range`
|
||||||
|
* @param {number|Array} range
|
||||||
|
* @param {Array} bound
|
||||||
|
* @return {number|Array}
|
||||||
|
*/
|
||||||
|
const sanitizeRange = (range, bound) => {
|
||||||
|
if (typeof range === 'number') {
|
||||||
|
return clamp(Math.abs(range), ...bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (range.length === 1 || range[0] === range[1]) {
|
||||||
|
return clamp(Math.abs(range[0]), ...bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
Math.abs(clamp(range[0], ...bound)),
|
||||||
|
clamp(Math.abs(range[1]), ...bound),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} p
|
||||||
|
* @param {number} q
|
||||||
|
* @param {number} t
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
const hueToRgb = (p, q, t) => {
|
||||||
|
if (t < 0) {
|
||||||
|
t += 1;
|
||||||
|
} else if (t > 1) {
|
||||||
|
t -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t < 1 / 6) {
|
||||||
|
return p + ((q - p) * 6 * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t < 1 / 2) {
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t < 2 / 3) {
|
||||||
|
return p + ((q - p) * ((2 / 3) - t) * 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an HSL color to RGB
|
||||||
|
* @param {number} h Hue
|
||||||
|
* @param {number} s Saturation
|
||||||
|
* @param {number} l Lightness
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
const hslToRgb = (h, s, l) => {
|
||||||
|
let r;
|
||||||
|
let g;
|
||||||
|
let b;
|
||||||
|
|
||||||
|
h /= 360;
|
||||||
|
s /= 100;
|
||||||
|
l /= 100;
|
||||||
|
|
||||||
|
if (s === 0) {
|
||||||
|
// achromatic
|
||||||
|
r = g = b = l;
|
||||||
|
} else {
|
||||||
|
const q = l < 0.5
|
||||||
|
? l * (1 + s)
|
||||||
|
: (l + s) - (l * s);
|
||||||
|
const p = (2 * l) - q;
|
||||||
|
|
||||||
|
r = hueToRgb(p, q, h + (1 / 3));
|
||||||
|
g = hueToRgb(p, q, h);
|
||||||
|
b = hueToRgb(p, q, h - (1 / 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
Math.round(r * 255),
|
||||||
|
Math.round(g * 255),
|
||||||
|
Math.round(b * 255),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the RGB color is light or not
|
||||||
|
* http://www.w3.org/TR/AERT#color-contrast
|
||||||
|
* @param {number} r Red
|
||||||
|
* @param {number} g Green
|
||||||
|
* @param {number} b Blue
|
||||||
|
* @param {number} differencePoint
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const rgbIsLight = (r, g, b, differencePoint) => ((r * 299) + (g * 587) + (b * 114)) / 1000 >= differencePoint; // eslint-disable-line max-len
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an HSL color to string format
|
||||||
|
* @param {number} h Hue
|
||||||
|
* @param {number} s Saturation
|
||||||
|
* @param {number} l Lightness
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
const hslToString = (h, s, l) => `hsl(${h}, ${s}%, ${l}%)`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts RGB color to string format
|
||||||
|
* @param {number} r Red
|
||||||
|
* @param {number} g Green
|
||||||
|
* @param {number} b Blue
|
||||||
|
* @param {string} format Color format
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
const rgbFormat = (r, g, b, format) => {
|
||||||
|
switch (format) {
|
||||||
|
case 'rgb':
|
||||||
|
return `rgb(${r}, ${g}, ${b})`;
|
||||||
|
case 'hex':
|
||||||
|
default:
|
||||||
|
return `#${pad2(r.toString(16))}${pad2(g.toString(16))}${pad2(b.toString(16))}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate unique color from `value`
|
||||||
|
* @param {string|number} value
|
||||||
|
* @param {Object} [options={}]
|
||||||
|
* @param {string} [options.format='hex']
|
||||||
|
* The color format, it can be one of `hex`, `rgb` or `hsl`
|
||||||
|
* @param {number|Array} [options.saturation=[50, 55]]
|
||||||
|
* Determines the color saturation, it can be a number or a range between 0 and 100
|
||||||
|
* @param {number|Array} [options.lightness=[50, 60]]
|
||||||
|
* Determines the color lightness, it can be a number or a range between 0 and 100
|
||||||
|
* @param {number} [options.differencePoint=130]
|
||||||
|
* Determines the color brightness difference point. We use it to obtain the `isLight` value
|
||||||
|
* in the output, it can be a number between 0 and 255
|
||||||
|
* @return {Object}
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* uniqolor('Hello world!')
|
||||||
|
* // { color: "#5cc653", isLight: true }
|
||||||
|
*
|
||||||
|
* uniqolor('Hello world!', { format: 'rgb' })
|
||||||
|
* // { color: "rgb(92, 198, 83)", isLight: true }
|
||||||
|
*
|
||||||
|
* uniqolor('Hello world!', {
|
||||||
|
* saturation: 30,
|
||||||
|
* lightness: [70, 80],
|
||||||
|
* })
|
||||||
|
* // { color: "#afd2ac", isLight: true }
|
||||||
|
*
|
||||||
|
* uniqolor('Hello world!', {
|
||||||
|
* saturation: 30,
|
||||||
|
* lightness: [70, 80],
|
||||||
|
* differencePoint: 200,
|
||||||
|
* })
|
||||||
|
* // { color: "#afd2ac", isLight: false }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
const uniqolor = (value, {
|
||||||
|
format = 'hex',
|
||||||
|
saturation = [50, 55],
|
||||||
|
lightness = [50, 60],
|
||||||
|
differencePoint = 130,
|
||||||
|
} = {}) => {
|
||||||
|
const hash = Math.abs(hashCode(String(value)));
|
||||||
|
const h = boundHashCode(hash, [0, 360]);
|
||||||
|
const s = boundHashCode(hash, sanitizeRange(saturation, SATURATION_BOUND));
|
||||||
|
const l = boundHashCode(hash, sanitizeRange(lightness, LIGHTNESS_BOUND));
|
||||||
|
const [r, g, b] = hslToRgb(h, s, l);
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: format === 'hsl'
|
||||||
|
? hslToString(h, s, l)
|
||||||
|
: rgbFormat(r, g, b, format),
|
||||||
|
isLight: rgbIsLight(r, g, b, differencePoint),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate random color
|
||||||
|
* @param {Object} [options={}]
|
||||||
|
* @param {string} [options.format='hex']
|
||||||
|
* The color format, it can be one of `hex`, `rgb` or `hsl`
|
||||||
|
* @param {number|Array} [options.saturation=[50, 55]]
|
||||||
|
* Determines the color saturation, it can be a number or a range between 0 and 100
|
||||||
|
* @param {number|Array} [options.lightness=[50, 60]]
|
||||||
|
* Determines the color lightness, it can be a number or a range between 0 and 100
|
||||||
|
* @param {number} [options.differencePoint=130]
|
||||||
|
* Determines the color brightness difference point. We use it to obtain the `isLight` value
|
||||||
|
* in the output, it can be a number between 0 and 255
|
||||||
|
* @param {Array} [options.excludeHue]
|
||||||
|
* Exclude certain hue ranges. For example to exclude red color range: `[[0, 20], [325, 359]]`
|
||||||
|
* @return {Object}
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* // Generate random color
|
||||||
|
* uniqolor.random()
|
||||||
|
* // { color: "#644cc8", isLight: false }
|
||||||
|
*
|
||||||
|
* // Generate a random color with HSL format
|
||||||
|
* uniqolor.random({ format: 'hsl' })
|
||||||
|
* // { color: "hsl(89, 55%, 60%)", isLight: true }
|
||||||
|
*
|
||||||
|
* // Generate a random color in specific saturation and lightness
|
||||||
|
* uniqolor.random({
|
||||||
|
* saturation: 80,
|
||||||
|
* lightness: [70, 80],
|
||||||
|
* })
|
||||||
|
* // { color: "#c7b9da", isLight: true }
|
||||||
|
*
|
||||||
|
* // Generate a random color but exclude red color range
|
||||||
|
* uniqolor.random({
|
||||||
|
* excludeHue: [[0, 20], [325, 359]],
|
||||||
|
* })
|
||||||
|
* // {color: '#53caab', isLight: true}
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
uniqolor.random = ({
|
||||||
|
format = 'hex',
|
||||||
|
saturation = [50, 55],
|
||||||
|
lightness = [50, 60],
|
||||||
|
differencePoint = 130,
|
||||||
|
excludeHue,
|
||||||
|
} = {}) => {
|
||||||
|
saturation = sanitizeRange(saturation, SATURATION_BOUND);
|
||||||
|
lightness = sanitizeRange(lightness, LIGHTNESS_BOUND);
|
||||||
|
|
||||||
|
const h = excludeHue ? randomExclude(0, 359, excludeHue) : random(0, 359);
|
||||||
|
const s = typeof saturation === 'number'
|
||||||
|
? saturation
|
||||||
|
: random(...saturation);
|
||||||
|
const l = typeof lightness === 'number'
|
||||||
|
? lightness
|
||||||
|
: random(...lightness);
|
||||||
|
const [r, g, b] = hslToRgb(h, s, l);
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: format === 'hsl'
|
||||||
|
? hslToString(h, s, l)
|
||||||
|
: rgbFormat(r, g, b, format),
|
||||||
|
isLight: rgbIsLight(r, g, b, differencePoint),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default uniqolor;
|
@ -189,3 +189,30 @@ export function sortByCssOrder(a, b) {
|
|||||||
const _b = Number($(b).css('order'));
|
const _b = Number($(b).css('order'));
|
||||||
return _a - _b;
|
return _a - _b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function end_trim_to_sentence(input, include_newline = false) {
|
||||||
|
// inspired from https://github.com/kaihordewebui/kaihordewebui.github.io/blob/06b95e6b7720eb85177fbaf1a7f52955d7cdbc02/index.html#L4853-L4867
|
||||||
|
|
||||||
|
const punctuation = new Set(['.', '!', '?', '*', '"', ')', '}', '`', ']', '$']); // extend this as you see fit
|
||||||
|
let last = -1;
|
||||||
|
|
||||||
|
for (let i = input.length - 1; i >= 0; i--) {
|
||||||
|
const char = input[i];
|
||||||
|
|
||||||
|
if (punctuation.has(char)) {
|
||||||
|
last = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (include_newline && char === '\n') {
|
||||||
|
last = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last === -1) {
|
||||||
|
return input.trimEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
return input.substring(0, last + 1).trimEnd();
|
||||||
|
}
|
||||||
|
@ -311,7 +311,7 @@ function appendWorldEntry(entry) {
|
|||||||
const value = $(this).prop("checked");
|
const value = $(this).prop("checked");
|
||||||
world_info_data.entries[uid].disable = value;
|
world_info_data.entries[uid].disable = value;
|
||||||
saveWorldInfo();
|
saveWorldInfo();
|
||||||
console.log(`WI #${entry.uid} disabled? ${world_info_data.entries[uid].disable}`);
|
//console.log(`WI #${entry.uid} disabled? ${world_info_data.entries[uid].disable}`);
|
||||||
});
|
});
|
||||||
disableInput.prop("checked", entry.disable).trigger("input");
|
disableInput.prop("checked", entry.disable).trigger("input");
|
||||||
disableInput.siblings(".checkbox_fancy").click(function () {
|
disableInput.siblings(".checkbox_fancy").click(function () {
|
||||||
@ -593,7 +593,8 @@ $(document).ready(() => {
|
|||||||
await loadWorldInfoData();
|
await loadWorldInfoData();
|
||||||
}
|
}
|
||||||
|
|
||||||
hideWorldEditor();
|
if (selectedWorld === "None") { hideWorldEditor(); }
|
||||||
|
if (is_world_edit_open && selectedWorld !== "None") { showWorldEditor() };
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
191
public/style.css
191
public/style.css
@ -132,6 +132,19 @@ table.responsiveTable {
|
|||||||
border-top: 2px solid grey;
|
border-top: 2px solid grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tokenItemizingSubclass {
|
||||||
|
font-size: calc(var(--mainFontSize) * 0.8);
|
||||||
|
color: var(--SmartThemeEmColor);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tokenGraph {
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid var(--white30a);
|
||||||
|
max-height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.fa-solid::before,
|
.fa-solid::before,
|
||||||
.fa-regular::before {
|
.fa-regular::before {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
@ -191,6 +204,16 @@ table.responsiveTable {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mes_narrate,
|
||||||
|
body.tts .mes[is_user="true"] .mes_narrate,
|
||||||
|
body.tts .mes[is_system="true"] .mes_narrate {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.tts .mes_narrate {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: Consolas, monospace;
|
font-family: Consolas, monospace;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
@ -373,6 +396,18 @@ code {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#token_breakdown div {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token_breakdown_segment {
|
||||||
|
min-width: 40px !important;
|
||||||
|
border: solid 2px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#loading_mes {
|
#loading_mes {
|
||||||
display: none;
|
display: none;
|
||||||
@ -814,6 +849,8 @@ select {
|
|||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
@ -878,19 +915,22 @@ input[type="file"] {
|
|||||||
|
|
||||||
#rm_button_characters,
|
#rm_button_characters,
|
||||||
#rm_button_panel_pin_div,
|
#rm_button_panel_pin_div,
|
||||||
#lm_button_panel_pin_div {
|
#lm_button_panel_pin_div,
|
||||||
|
#WI_button_panel_pin_div {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rm_button_panel_pin_div,
|
#rm_button_panel_pin_div,
|
||||||
#lm_button_panel_pin_div {
|
#lm_button_panel_pin_div,
|
||||||
|
#WI_button_panel_pin_div {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
transition: 0.3s;
|
transition: 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rm_button_panel_pin_div:hover,
|
#rm_button_panel_pin_div:hover,
|
||||||
#lm_button_panel_pin_div:hover {
|
#lm_button_panel_pin_div:hover,
|
||||||
|
#WI_button_panel_pin_div:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -899,32 +939,38 @@ input[type="file"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#rm_button_panel_pin,
|
#rm_button_panel_pin,
|
||||||
#lm_button_panel_pin {
|
#lm_button_panel_pin,
|
||||||
|
#WI_panel_pin {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rm_button_panel_pin:checked+label,
|
#rm_button_panel_pin:checked+label,
|
||||||
#lm_button_panel_pin:checked+label {
|
#lm_button_panel_pin:checked+label,
|
||||||
|
#WI_panel_pin:checked+label {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rm_button_panel_pin:checked+label .checked,
|
#rm_button_panel_pin:checked+label .checked,
|
||||||
#lm_button_panel_pin:checked+label .checked {
|
#lm_button_panel_pin:checked+label .checked,
|
||||||
|
#WI_panel_pin:checked+label .checked {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rm_button_panel_pin:checked+label .unchecked,
|
#rm_button_panel_pin:checked+label .unchecked,
|
||||||
#lm_button_panel_pin:checked+label .unchecked {
|
#lm_button_panel_pin:checked+label .unchecked,
|
||||||
|
#WI_panel_pin:checked+label .unchecked {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rm_button_panel_pin:not(:checked)+label .checked,
|
#rm_button_panel_pin:not(:checked)+label .checked,
|
||||||
#lm_button_panel_pin:not(:checked)+label .checked {
|
#lm_button_panel_pin:not(:checked)+label .checked,
|
||||||
|
#WI_panel_pin:not(:checked)+label .checked {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rm_button_panel_pin:not(:checked)+label .unchecked,
|
#rm_button_panel_pin:not(:checked)+label .unchecked,
|
||||||
#lm_button_panel_pin:not(:checked)+label .unchecked {
|
#lm_button_panel_pin:not(:checked)+label .unchecked,
|
||||||
|
#WI_panel_pin:not(:checked)+label .unchecked {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1034,15 +1080,10 @@ select option:not(:checked) {
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#api_url_text,
|
#api_url_text {
|
||||||
#textgenerationwebui_api_url_text {
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
#textgenerationwebui_api pre {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#api_button:hover,
|
#api_button:hover,
|
||||||
#api_button_novel:hover,
|
#api_button_novel:hover,
|
||||||
#api_button_textgenerationwebui:hover,
|
#api_button_textgenerationwebui:hover,
|
||||||
@ -1168,6 +1209,10 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
width: calc(100% - 70px);
|
width: calc(100% - 70px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.widthUnset {
|
||||||
|
width: unset;
|
||||||
|
}
|
||||||
|
|
||||||
#avatar_url_div {
|
#avatar_url_div {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -1516,6 +1561,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar_div .menu_button,
|
.avatar_div .menu_button,
|
||||||
@ -1636,29 +1682,32 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
|
|
||||||
#world_popup {
|
#world_popup {
|
||||||
display: none;
|
display: none;
|
||||||
background-color: var(--SmartThemeBlurTintColor);
|
/* background-color: var(--SmartThemeBlurTintColor);
|
||||||
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2));
|
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2)); */
|
||||||
max-width: var(--sheldWidth);
|
/* max-width: var(--sheldWidth); */
|
||||||
height: calc(100% - 40px);
|
/* max-height: calc(100% - 100px); */
|
||||||
position: absolute;
|
min-height: 100px;
|
||||||
margin-left: auto;
|
min-width: 100px;
|
||||||
margin-right: auto;
|
/* position: absolute; */
|
||||||
|
/* margin-left: auto;
|
||||||
|
margin-right: auto; */
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 40px;
|
/* top: 40px; */
|
||||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
|
/* box-shadow: 0 0 2px rgba(0, 0, 0, 0.5); */
|
||||||
padding: 4px;
|
/* padding: 10px; */
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
z-index: 3010;
|
z-index: 3010;
|
||||||
border-radius: 0 0 20px 20px;
|
border-radius: 0 0 20px 20px;
|
||||||
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#world_popup_bottom_holder {
|
#world_popup_bottom_holder {
|
||||||
padding: 0.5rem 0;
|
/* padding: 0.5rem 0;
|
||||||
margin: 0 18px;
|
margin: 0 18px; */
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: flex-end;
|
justify-content: space-evenly;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1677,6 +1726,10 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.world_entry {
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.world_entry:not(:last-child)::after {
|
.world_entry:not(:last-child)::after {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
@ -1695,7 +1748,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-left: 18px;
|
/* margin-left: 18px; */
|
||||||
}
|
}
|
||||||
|
|
||||||
#world_popup_header h3 {
|
#world_popup_header h3 {
|
||||||
@ -1712,7 +1765,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#form_rename_world {
|
#form_rename_world {
|
||||||
margin-right: 50px;
|
/* margin-right: 50px; */
|
||||||
}
|
}
|
||||||
|
|
||||||
#form_rename_chat {
|
#form_rename_chat {
|
||||||
@ -1741,7 +1794,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
|
|
||||||
#world_popup_entries_list {
|
#world_popup_entries_list {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
overflow-y: scroll;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#world_popup_entries_list:empty {
|
#world_popup_entries_list:empty {
|
||||||
@ -1792,7 +1845,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
|
|
||||||
.world_entry_form_control textarea {
|
.world_entry_form_control textarea {
|
||||||
height: auto;
|
height: auto;
|
||||||
width: auto;
|
/* width: auto; */
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1800,6 +1853,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.world_entry_form_control input[type=button] {
|
.world_entry_form_control input[type=button] {
|
||||||
@ -2131,6 +2185,8 @@ input[type="range"]::-webkit-slider-thumb {
|
|||||||
right: 0px;
|
right: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mes_prompt,
|
||||||
|
.mes_narrate,
|
||||||
.mes_copy,
|
.mes_copy,
|
||||||
.mes_edit {
|
.mes_edit {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -2143,11 +2199,14 @@ input[type="range"]::-webkit-slider-thumb {
|
|||||||
|
|
||||||
.mes_edit:hover,
|
.mes_edit:hover,
|
||||||
.mes_copy:hover,
|
.mes_copy:hover,
|
||||||
|
.mes_narrate:hover,
|
||||||
.mes_stop:hover {
|
.mes_stop:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.last_mes .mes_copy {
|
.last_mes .mes_copy,
|
||||||
|
.last_mes .mes_narrate,
|
||||||
|
.last_mes .mes_prompt {
|
||||||
grid-row-start: 1;
|
grid-row-start: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
right: -30px;
|
right: -30px;
|
||||||
@ -2256,8 +2315,10 @@ input[type="range"]::-webkit-slider-thumb {
|
|||||||
-webkit-backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)*2));
|
-webkit-backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)*2));
|
||||||
grid-template-rows: 50px 1fr 1fr 1fr 5fr;
|
grid-template-rows: 50px 1fr 1fr 1fr 5fr;
|
||||||
grid-gap: 10px;
|
grid-gap: 10px;
|
||||||
|
min-height: 100px;
|
||||||
|
min-width: 100px;
|
||||||
max-width: var(--sheldWidth);
|
max-width: var(--sheldWidth);
|
||||||
height: calc(100svh - 40px);
|
max-height: calc(100svh - 100px);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 3002;
|
z-index: 3002;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
@ -2272,6 +2333,7 @@ input[type="range"]::-webkit-slider-thumb {
|
|||||||
padding-bottom: 30px;
|
padding-bottom: 30px;
|
||||||
border: 1px solid var(--black30a);
|
border: 1px solid var(--black30a);
|
||||||
border-radius: 0 0 20px 20px;
|
border-radius: 0 0 20px 20px;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#character_popup h3 {
|
#character_popup h3 {
|
||||||
@ -2771,7 +2833,6 @@ body .ui-widget-content li:hover {
|
|||||||
#rm_group_add_members_header {
|
#rm_group_add_members_header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
column-gap: 10px;
|
column-gap: 10px;
|
||||||
}
|
}
|
||||||
@ -3134,11 +3195,39 @@ a {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#export_format_popup {
|
#export_format_popup,
|
||||||
|
#rawPromptPopup {
|
||||||
display: none;
|
display: none;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#rawPromptPopup {
|
||||||
|
inset: 0px auto auto 0px;
|
||||||
|
margin: 0px;
|
||||||
|
transform: translate(909px, 47px);
|
||||||
|
display: block;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
white-space: normal;
|
||||||
|
max-width: calc(((100svw - 500px) / 2) - 10px);
|
||||||
|
position: absolute;
|
||||||
|
z-index: 9999;
|
||||||
|
max-height: 90svh;
|
||||||
|
/*unsure why, but this prevents scrollbars*/
|
||||||
|
height: 49svh;
|
||||||
|
|
||||||
|
padding: 5px;
|
||||||
|
overflow-y: auto;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rawPopupWrapper {
|
||||||
|
word-wrap: break-word;
|
||||||
|
width: 100%;
|
||||||
|
text-align: start;
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.list-group {
|
.list-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -3437,11 +3526,15 @@ label[for="extensions_autoconnect"] {
|
|||||||
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)));
|
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)));
|
||||||
-webkit-backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)));
|
-webkit-backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)));
|
||||||
z-index: 9999 !important;
|
z-index: 9999 !important;
|
||||||
|
border: 1px solid var(--white30a);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fillRight,
|
.fillRight,
|
||||||
.fillLeft {
|
.fillLeft,
|
||||||
|
#WorldInfo,
|
||||||
|
#floatingPrompt {
|
||||||
min-width: unset;
|
min-width: unset;
|
||||||
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fillLeft {
|
.fillLeft {
|
||||||
@ -3796,7 +3889,8 @@ body.movingUI .drag-grabber {
|
|||||||
body.movingUI #sheld,
|
body.movingUI #sheld,
|
||||||
body.movingUI .drawer-content,
|
body.movingUI .drawer-content,
|
||||||
body.movingUI #expression-holder,
|
body.movingUI #expression-holder,
|
||||||
body.movingUI #avatar_zoom_popup {
|
body.movingUI #avatar_zoom_popup,
|
||||||
|
body.movingUI #floatingPrompt {
|
||||||
resize: both;
|
resize: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3949,10 +4043,10 @@ body.waifuMode #avatar_zoom_popup {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#world_popup_header {
|
/* #world_popup_header {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
} */
|
||||||
|
|
||||||
#world_popup_header .world_popup_expander {
|
#world_popup_header .world_popup_expander {
|
||||||
display: none;
|
display: none;
|
||||||
@ -3998,14 +4092,18 @@ body.waifuMode #avatar_zoom_popup {
|
|||||||
|
|
||||||
#sheld,
|
#sheld,
|
||||||
#character_popup,
|
#character_popup,
|
||||||
#world_popup {
|
.drawer-content
|
||||||
height: calc(100svh - 45px);
|
|
||||||
|
/* ,
|
||||||
|
#world_popup */
|
||||||
|
{
|
||||||
|
max-height: calc(100svh - 45px);
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
left: 0 !important;
|
left: 0 !important;
|
||||||
resize: none;
|
resize: none !important;
|
||||||
top: 42px;
|
top: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#character_popup,
|
#character_popup,
|
||||||
@ -4014,7 +4112,6 @@ body.waifuMode #avatar_zoom_popup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#character_popup,
|
#character_popup,
|
||||||
#world_popup,
|
|
||||||
#send_form {
|
#send_form {
|
||||||
border: 1px solid var(--grey30);
|
border: 1px solid var(--grey30);
|
||||||
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2));
|
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2));
|
||||||
@ -4036,6 +4133,10 @@ body.waifuMode #avatar_zoom_popup {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#showRawPrompt {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.mes-text {
|
.mes-text {
|
||||||
padding-right: 25px;
|
padding-right: 25px;
|
||||||
}
|
}
|
||||||
|
23
readme.md
23
readme.md
@ -136,8 +136,8 @@ Easy to follow guide with pretty pictures:
|
|||||||
5. Open a Command Prompt inside that folder by clicking in the 'Address Bar' at the top, typing `cmd`, and pressing Enter.
|
5. Open a Command Prompt inside that folder by clicking in the 'Address Bar' at the top, typing `cmd`, and pressing Enter.
|
||||||
6. Once the black box (Command Prompt) pops up, type ONE of the following into it and press Enter:
|
6. Once the black box (Command Prompt) pops up, type ONE of the following into it and press Enter:
|
||||||
|
|
||||||
* for Main Branch: `git clone https://github.com/Cohee1207/SillyTavern -b main`
|
* for Main Branch: `git clone https://github.com/Cohee1207/SillyTavern -b main`
|
||||||
* for Dev Branch: `git clone https://github.com/Cohee1207/SillyTavern -b dev`
|
* for Dev Branch: `git clone https://github.com/Cohee1207/SillyTavern -b dev`
|
||||||
|
|
||||||
7. Once everything is cloned, double click `Start.bat` to make NodeJS install its requirements.
|
7. Once everything is cloned, double click `Start.bat` to make NodeJS install its requirements.
|
||||||
8. The server will then start, and SillyTavern will popup in your browser.
|
8. The server will then start, and SillyTavern will popup in your browser.
|
||||||
@ -179,13 +179,23 @@ However, it can be used to allow remote connections from anywhere as well.
|
|||||||
* Create a new text file inside your SillyTavern base install folder called `whitelist.txt`.
|
* Create a new text file inside your SillyTavern base install folder called `whitelist.txt`.
|
||||||
* Open the file in a text editor, add a list of IPs you want to be allowed to connect.
|
* Open the file in a text editor, add a list of IPs you want to be allowed to connect.
|
||||||
|
|
||||||
*IP ranges are not accepted. Each IP must be listed individually like this:*
|
*Both indidivual IPs, and wildcard IP ranges are accepted. Examples:*
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
192.168.0.1
|
192.168.0.1
|
||||||
192.168.0.2
|
192.168.0.20
|
||||||
192.168.0.3
|
|
||||||
192.168.0.4
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```txt
|
||||||
|
192.168.0.*
|
||||||
|
```
|
||||||
|
|
||||||
|
(the above wildcard IP range will allow any device on the local network to connect)
|
||||||
|
|
||||||
|
CIDR masks are also accepted (eg. 10.0.0.0/24).
|
||||||
|
|
||||||
* Save the `whitelist.txt` file.
|
* Save the `whitelist.txt` file.
|
||||||
* Restart your TAI server.
|
* Restart your TAI server.
|
||||||
|
|
||||||
@ -272,5 +282,6 @@ GNU Affero General Public License for more details.**
|
|||||||
* KoboldAI Presets from KAI Lite: <https://lite.koboldai.net/>
|
* KoboldAI Presets from KAI Lite: <https://lite.koboldai.net/>
|
||||||
* Noto Sans font by Google (OFL license)
|
* Noto Sans font by Google (OFL license)
|
||||||
* Icon theme by Font Awesome <https://fontawesome.com> (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
* Icon theme by Font Awesome <https://fontawesome.com> (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* AI Horde client library by ZeldaFan0225: https://github.com/ZeldaFan0225/ai_horde
|
||||||
* Linux startup script by AlpinDale
|
* Linux startup script by AlpinDale
|
||||||
* Thanks paniphons for providing a FAQ document
|
* Thanks paniphons for providing a FAQ document
|
||||||
|
134
server.js
134
server.js
@ -85,6 +85,11 @@ const allowKeysExposure = config.allowKeysExposure;
|
|||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const tiktoken = require('@dqbd/tiktoken');
|
const tiktoken = require('@dqbd/tiktoken');
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
|
const AIHorde = require("./src/horde");
|
||||||
|
const ai_horde = new AIHorde({
|
||||||
|
client_agent: getVersion()?.agent || 'SillyTavern:UNKNOWN:Cohee#1207',
|
||||||
|
});
|
||||||
|
const ipMatching = require('ip-matching');
|
||||||
|
|
||||||
var Client = require('node-rest-client').Client;
|
var Client = require('node-rest-client').Client;
|
||||||
var client = new Client();
|
var client = new Client();
|
||||||
@ -242,7 +247,7 @@ app.use(function (req, res, next) { //Security
|
|||||||
}
|
}
|
||||||
|
|
||||||
//clientIp = req.connection.remoteAddress.split(':').pop();
|
//clientIp = req.connection.remoteAddress.split(':').pop();
|
||||||
if (whitelistMode === true && !whitelist.includes(clientIp)) {
|
if (whitelistMode === true && !whitelist.some(x => ipMatching.matches(clientIp, ipMatching.getMatch(x)))) {
|
||||||
console.log('Forbidden: Connection attempt from ' + clientIp + '. If you are attempting to connect, please add your IP address in whitelist or disable whitelist mode in config.conf in root of SillyTavern folder.\n');
|
console.log('Forbidden: Connection attempt from ' + clientIp + '. If you are attempting to connect, please add your IP address in whitelist or disable whitelist mode in config.conf in root of SillyTavern folder.\n');
|
||||||
return res.status(403).send('<b>Forbidden</b>: Connection attempt from <b>' + clientIp + '</b>. If you are attempting to connect, please add your IP address in whitelist or disable whitelist mode in config.conf in root of SillyTavern folder.');
|
return res.status(403).send('<b>Forbidden</b>: Connection attempt from <b>' + clientIp + '</b>. If you are attempting to connect, please add your IP address in whitelist or disable whitelist mode in config.conf in root of SillyTavern folder.');
|
||||||
}
|
}
|
||||||
@ -312,27 +317,8 @@ app.get('/deviceinfo', function (request, response) {
|
|||||||
return response.send(deviceInfo);
|
return response.send(deviceInfo);
|
||||||
});
|
});
|
||||||
app.get('/version', function (_, response) {
|
app.get('/version', function (_, response) {
|
||||||
let pkgVersion, gitRevision, gitBranch;
|
const data = getVersion();
|
||||||
try {
|
response.send(data);
|
||||||
const pkgJson = require('./package.json');
|
|
||||||
pkgVersion = pkgJson.version;
|
|
||||||
if (commandExistsSync('git')) {
|
|
||||||
gitRevision = require('child_process')
|
|
||||||
.execSync('git rev-parse --short HEAD', { cwd: process.cwd() })
|
|
||||||
.toString().trim();
|
|
||||||
|
|
||||||
gitBranch = require('child_process')
|
|
||||||
.execSync('git rev-parse --abbrev-ref HEAD', { cwd: process.cwd() })
|
|
||||||
.toString().trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
// suppress exception
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
const agent = `SillyTavern:${gitRevision || pkgVersion}:Cohee#1207`;
|
|
||||||
response.send({ agent, pkgVersion, gitRevision, gitBranch });
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
//**************Kobold api
|
//**************Kobold api
|
||||||
@ -531,7 +517,7 @@ app.post("/savechat", jsonParser, function (request, response) {
|
|||||||
var dir_name = String(request.body.avatar_url).replace('.png', '');
|
var dir_name = String(request.body.avatar_url).replace('.png', '');
|
||||||
let chat_data = request.body.chat;
|
let chat_data = request.body.chat;
|
||||||
let jsonlData = chat_data.map(JSON.stringify).join('\n');
|
let jsonlData = chat_data.map(JSON.stringify).join('\n');
|
||||||
fs.writeFile(chatsPath + dir_name + "/" + request.body.file_name + '.jsonl', jsonlData, 'utf8', function (err) {
|
fs.writeFile(`${chatsPath + dir_name}/${sanitize(request.body.file_name)}.jsonl`, jsonlData, 'utf8', function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
response.send(err);
|
response.send(err);
|
||||||
return console.log(err);
|
return console.log(err);
|
||||||
@ -555,11 +541,10 @@ app.post("/getchat", jsonParser, function (request, response) {
|
|||||||
|
|
||||||
if (err === null) { //if there is a dir, then read the requested file from the JSON call
|
if (err === null) { //if there is a dir, then read the requested file from the JSON call
|
||||||
|
|
||||||
fs.stat(chatsPath + dir_name + "/" + request.body.file_name + ".jsonl", function (err, stat) {
|
fs.stat(`${chatsPath + dir_name}/${sanitize(request.body.file_name)}.jsonl`, function (err, stat) {
|
||||||
|
|
||||||
if (err === null) { //if no error (the file exists), read the file
|
if (err === null) { //if no error (the file exists), read the file
|
||||||
if (stat !== undefined) {
|
if (stat !== undefined) {
|
||||||
fs.readFile(chatsPath + dir_name + "/" + request.body.file_name + ".jsonl", 'utf8', (err, data) => {
|
fs.readFile(`${chatsPath + dir_name}/${sanitize(request.body.file_name)}.jsonl`, 'utf8', (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
response.send(err);
|
response.send(err);
|
||||||
@ -588,9 +573,8 @@ app.post("/getchat", jsonParser, function (request, response) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/getstatus", jsonParser, async function (request, response_getstatus = response) {
|
app.post("/getstatus", jsonParser, async function (request, response_getstatus = response) {
|
||||||
if (!request.body) return response_getstatus.sendStatus(400);
|
if (!request.body) return response_getstatus.sendStatus(400);
|
||||||
api_server = request.body.api_server;
|
api_server = request.body.api_server;
|
||||||
@ -670,6 +654,31 @@ app.post("/setsoftprompt", jsonParser, async function (request, response) {
|
|||||||
return response.sendStatus(200);
|
return response.sendStatus(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getVersion() {
|
||||||
|
let pkgVersion = 'UNKNOWN';
|
||||||
|
let gitRevision = null;
|
||||||
|
let gitBranch = null;
|
||||||
|
try {
|
||||||
|
const pkgJson = require('./package.json');
|
||||||
|
pkgVersion = pkgJson.version;
|
||||||
|
if (!process.pkg && commandExistsSync('git')) {
|
||||||
|
gitRevision = require('child_process')
|
||||||
|
.execSync('git rev-parse --short HEAD', { cwd: process.cwd() })
|
||||||
|
.toString().trim();
|
||||||
|
|
||||||
|
gitBranch = require('child_process')
|
||||||
|
.execSync('git rev-parse --abbrev-ref HEAD', { cwd: process.cwd() })
|
||||||
|
.toString().trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// suppress exception
|
||||||
|
}
|
||||||
|
|
||||||
|
const agent = `SillyTavern:${pkgVersion}:Cohee#1207`;
|
||||||
|
return { agent, pkgVersion, gitRevision, gitBranch };
|
||||||
|
}
|
||||||
|
|
||||||
function tryParse(str) {
|
function tryParse(str) {
|
||||||
try {
|
try {
|
||||||
return json5.parse(str);
|
return json5.parse(str);
|
||||||
@ -1284,7 +1293,7 @@ app.post('/getsettings', jsonParser, (request, response) => { //Wintermute's cod
|
|||||||
.filter(x => path.parse(x).ext == '.json')
|
.filter(x => path.parse(x).ext == '.json')
|
||||||
.sort();
|
.sort();
|
||||||
|
|
||||||
instructFiles.forEach(item => {
|
instructFiles.forEach(item => {
|
||||||
const file = fs.readFileSync(
|
const file = fs.readFileSync(
|
||||||
path.join(directories.instruct, item),
|
path.join(directories.instruct, item),
|
||||||
'utf-8',
|
'utf-8',
|
||||||
@ -2557,7 +2566,8 @@ app.post("/generate_openai", jsonParser, function (request, response_generate_op
|
|||||||
response_generate_openai.send({ error: true });
|
response_generate_openai.send({ error: true });
|
||||||
} else if (response.status == 429) {
|
} else if (response.status == 429) {
|
||||||
console.log('Out of quota');
|
console.log('Out of quota');
|
||||||
response_generate_openai.send({ error: true, quota_error: true, });
|
const quota_error = response?.data?.type === 'insufficient_quota';
|
||||||
|
response_generate_openai.send({ error: true, quota_error, });
|
||||||
} else if (response.status == 500 || response.status == 409 || response.status == 504) {
|
} else if (response.status == 500 || response.status == 409 || response.status == 504) {
|
||||||
if (request.body.stream) {
|
if (request.body.stream) {
|
||||||
response.data.on('data', chunk => {
|
response.data.on('data', chunk => {
|
||||||
@ -2580,7 +2590,7 @@ app.post("/generate_openai", jsonParser, function (request, response_generate_op
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const quota_error = error?.response?.status === 429;
|
const quota_error = error?.response?.status === 429 && error?.response?.data?.error?.type === 'insufficient_quota';
|
||||||
if (!response_generate_openai.headersSent) {
|
if (!response_generate_openai.headersSent) {
|
||||||
response_generate_openai.send({ error: true, quota_error });
|
response_generate_openai.send({ error: true, quota_error });
|
||||||
}
|
}
|
||||||
@ -2856,7 +2866,7 @@ app.post('/writesecret', jsonParser, (request, response) => {
|
|||||||
const key = request.body.key;
|
const key = request.body.key;
|
||||||
const value = request.body.value;
|
const value = request.body.value;
|
||||||
|
|
||||||
writeSecret(key,value);
|
writeSecret(key, value);
|
||||||
return response.send('ok');
|
return response.send('ok');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2881,8 +2891,9 @@ app.post('/readsecretstate', jsonParser, (_, response) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ANONYMOUS_KEY = "0000000000";
|
||||||
|
|
||||||
app.post('/generate_horde', jsonParser, async (request, response) => {
|
app.post('/generate_horde', jsonParser, async (request, response) => {
|
||||||
const ANONYMOUS_KEY = "0000000000";
|
|
||||||
const api_key_horde = readSecret(SECRET_KEYS.HORDE) || ANONYMOUS_KEY;
|
const api_key_horde = readSecret(SECRET_KEYS.HORDE) || ANONYMOUS_KEY;
|
||||||
const url = 'https://horde.koboldai.net/api/v2/generate/text/async';
|
const url = 'https://horde.koboldai.net/api/v2/generate/text/async';
|
||||||
|
|
||||||
@ -2925,6 +2936,63 @@ app.post('/viewsecrets', jsonParser, async (_, response) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post('/horde_samplers', jsonParser, async (_, response) => {
|
||||||
|
const samplers = Object.values(ai_horde.ModelGenerationInputStableSamplers);
|
||||||
|
response.send(samplers);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/horde_models', jsonParser, async (_, response) => {
|
||||||
|
const models = await ai_horde.getModels();
|
||||||
|
response.send(models);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/horde_generateimage', jsonParser, async (request, response) => {
|
||||||
|
const MAX_ATTEMPTS = 100;
|
||||||
|
const CHECK_INTERVAL = 3000;
|
||||||
|
const api_key_horde = readSecret(SECRET_KEYS.HORDE) || ANONYMOUS_KEY;
|
||||||
|
console.log('Stable Horde request:', request.body);
|
||||||
|
const generation = await ai_horde.postAsyncImageGenerate(
|
||||||
|
{
|
||||||
|
prompt: `${request.body.prompt_prefix} ${request.body.prompt} ### ${request.body.negative_prompt}`,
|
||||||
|
params:
|
||||||
|
{
|
||||||
|
sampler_name: request.body.sampler,
|
||||||
|
cfg_scale: request.body.scale,
|
||||||
|
steps: request.body.steps,
|
||||||
|
width: request.body.width,
|
||||||
|
height: request.body.height,
|
||||||
|
n: 1,
|
||||||
|
},
|
||||||
|
r2: false,
|
||||||
|
nsfw: request.body.nfsw,
|
||||||
|
models: [request.body.model],
|
||||||
|
},
|
||||||
|
{ token: api_key_horde });
|
||||||
|
|
||||||
|
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
||||||
|
await delay(CHECK_INTERVAL);
|
||||||
|
const check = await ai_horde.getImageGenerationCheck(generation.id);
|
||||||
|
console.log(check);
|
||||||
|
|
||||||
|
if (check.done) {
|
||||||
|
const result = await ai_horde.getImageGenerationStatus(generation.id);
|
||||||
|
return response.send(result.generations[0].img);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (!check.is_possible) {
|
||||||
|
return response.sendStatus(503);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (check.faulted) {
|
||||||
|
return response.sendStatus(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.sendStatus(504);
|
||||||
|
});
|
||||||
|
|
||||||
function writeSecret(key, value) {
|
function writeSecret(key, value) {
|
||||||
if (!fs.existsSync(SECRETS_FILE)) {
|
if (!fs.existsSync(SECRETS_FILE)) {
|
||||||
const emptyFile = JSON.stringify({});
|
const emptyFile = JSON.stringify({});
|
||||||
|
21
src/horde/LICENSE.md
Normal file
21
src/horde/LICENSE.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 ZeldaFan0225
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
2189
src/horde/index.d.ts
vendored
Normal file
2189
src/horde/index.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
src/horde/index.js
Normal file
1
src/horde/index.js
Normal file
File diff suppressed because one or more lines are too long
3
src/horde/index.mjs
Normal file
3
src/horde/index.mjs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import AIHorde from './index.js'
|
||||||
|
export default AIHorde
|
||||||
|
export { AIHorde }
|
3
start.sh
3
start.sh
@ -10,7 +10,8 @@ then
|
|||||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
|
||||||
source ~/.bashrc
|
source ~/.bashrc
|
||||||
nvm install node;;
|
nvm install lts
|
||||||
|
nvm use lts;;
|
||||||
n|N )
|
n|N )
|
||||||
echo "Nodejs and npm will not be installed."
|
echo "Nodejs and npm will not be installed."
|
||||||
exit;;
|
exit;;
|
||||||
|
Reference in New Issue
Block a user