Merge branch 'dev' into dev

This commit is contained in:
Cohee
2023-06-12 23:13:16 +03:00
committed by GitHub
15 changed files with 537 additions and 279 deletions

View File

@ -104,7 +104,7 @@
<div id="lm_button_panel_pin_div" title="Locked = AI Configuration panel will stay open"> <div id="lm_button_panel_pin_div" title="Locked = AI Configuration panel will stay open">
<input type="checkbox" id="lm_button_panel_pin"> <input type="checkbox" id="lm_button_panel_pin">
<label for="lm_button_panel_pin"> <label for="lm_button_panel_pin">
<div class="unchecked fa-solid fa-lock-open "></div> <div class="unchecked fa-solid fa-unlock "></div>
<div class="checked fa-solid fa-lock "></div> <div class="checked fa-solid fa-lock "></div>
</label> </label>
</div> </div>
@ -116,7 +116,7 @@
<div id="respective-presets-block" class="width100p"> <div id="respective-presets-block" class="width100p">
<div id="kobold_api-presets"> <div id="kobold_api-presets">
<h3><span data-i18n="kobldpresets">Kobold Presets</span> <h3><span data-i18n="kobldpresets">Kobold Presets</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#koboldai" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/api-connections/koboldai/" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</h3> </h3>
@ -127,7 +127,7 @@
<div id="novel_api-presets"> <div id="novel_api-presets">
<h3> <h3>
<span data-i18n="novelaipreserts">NovelAI Presets</span> <span data-i18n="novelaipreserts">NovelAI Presets</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#novelai" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/api-connections/novelai/" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</h3> </h3>
@ -340,7 +340,7 @@
</div> </div>
<div class="range-block-range-and-counter"> <div class="range-block-range-and-counter">
<div class="range-block-range"> <div class="range-block-range">
<input type="range" id="rep_pen_slope_novel" name="volume" min="0" max="10" step="0.01"> <input type="range" id="rep_pen_slope_novel" name="volume" min="0.01" max="10" step="0.01">
</div> </div>
<div class="range-block-counter"> <div class="range-block-counter">
<div contenteditable="true" data-for="rep_pen_slope_novel" id="rep_pen_slope_counter_novel"> <div contenteditable="true" data-for="rep_pen_slope_novel" id="rep_pen_slope_counter_novel">
@ -625,6 +625,12 @@
Use "Unlocked Context" to enable chunked generation. Use "Unlocked Context" to enable chunked generation.
It extends the context window in exchange for reply generation speed. It extends the context window in exchange for reply generation speed.
</div> </div>
<h4>Safe Context Size values for Poe bots:</h4>
<ul class="margin0auto">
<li>ChatGPT / Sage = 3600-4000 tokens</li>
<li>Claude-instant / Claude+ = 5000-5500 tokens</li>
<li>GPT-4 = 7600-8000 tokens</li>
</ul>
<div class="flex-container spaceEvenly"> <div class="flex-container spaceEvenly">
<div id="poe_send_jailbreak" class="menu_button widthFitContent" title="Attempts to automatically jailbreak the bot"> <div id="poe_send_jailbreak" class="menu_button widthFitContent" title="Attempts to automatically jailbreak the bot">
Send Jailbreak Send Jailbreak
@ -1293,12 +1299,12 @@
</label> </label>
<h4>API key</h4> <h4>API key</h4>
<h5>Get it here: <a target="_blank" href="https://horde.koboldai.net/register">Register</a><br> <small>Get it here: <a target="_blank" href="https://horde.koboldai.net/register">Register</a> (<a id="horde_kudos" href="javascript:void(0);">View my Kudos</a>)<br>
Enter <span class="monospace">0000000000</span> to use anonymous mode. Enter <span class="monospace">0000000000</span> to use anonymous mode.
</h5> </small>
<div> <!-- <div>
<a id="horde_kudos" href="javascript:void(0);">View my Kudos</a> <a id="horde_kudos" href="javascript:void(0);">View my Kudos</a>
</div> </div> -->
<div class="flex-container"> <div class="flex-container">
<input id="horde_api_key" name="horde_api_key" class="text_pole flex1" maxlength="500" type="text" placeholder="0000000000" autocomplete="off"> <input id="horde_api_key" name="horde_api_key" class="text_pole flex1" maxlength="500" type="text" placeholder="0000000000" autocomplete="off">
<div title="Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_horde"></div> <div title="Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_horde"></div>
@ -1312,7 +1318,7 @@
</div> </div>
</h4> </h4>
<small class="horde_multiple_hint">You can select multiple models.<br>Avoid sending <small class="horde_multiple_hint">You can select multiple models.<br>Avoid sending
sensitive information to the Horde. <a id="horde_privacy_disclaimer" target="_blank" href="https://docs.sillytavern.app/usage/guidebook/#horde">Learn more</a></small> sensitive information to the Horde. <a id="horde_privacy_disclaimer" target="_blank" href="https://docs.sillytavern.app/usage/api-connections/koboldai/">Learn more</a></small>
<select id="horde_model" multiple> <select id="horde_model" multiple>
<option>-- Horde models not loaded --</option> <option>-- Horde models not loaded --</option>
</select> </select>
@ -1327,7 +1333,7 @@
<form action="javascript:void(null);" method="post" enctype="multipart/form-data"> <form action="javascript:void(null);" method="post" enctype="multipart/form-data">
<div id="kobold_api_block"> <div id="kobold_api_block">
<h4>API url</h4> <h4>API url</h4>
<h5>Example: http://127.0.0.1:5000/api </h5> <small>Example: http://127.0.0.1:5000/api </small>
<input id="api_url_text" name="api_url" class="text_pole" placeholder="http://127.0.0.1:5000/api" maxlength="500" value="" autocomplete="off"> <input id="api_url_text" name="api_url" class="text_pole" placeholder="http://127.0.0.1:5000/api" maxlength="500" value="" autocomplete="off">
<input id="api_button" class="menu_button" type="submit" value="Connect"> <input id="api_button" class="menu_button" type="submit" value="Connect">
<div id="api_loading" class="api-load-icon fa-solid fa-hourglass fa-spin"></div> <div id="api_loading" class="api-load-icon fa-solid fa-hourglass fa-spin"></div>
@ -1345,9 +1351,7 @@
<span> <span>
<ol> <ol>
<li> <li>
<span data-i18n="Follow">Follow</span> <a href="https://docs.sillytavern.app/usage/guidebook/#api-key" class="notes-link" target="_blank"> <span data-i18n="these directions">these <a href="https://docs.sillytavern.app/usage/api-connections/novelai/" class="notes-link" target="_blank"> <span data-i18n="Get your NovelAI API Key">Get your NovelAI API key</span></a>
directions</span> </a> <span data-i18n="to get your NovelAI API key.">to
get your NovelAI API key.</span>
</li> </li>
<li><span data-i18n="Enter it in the box below">Enter it in the box below:</span> <li><span data-i18n="Enter it in the box below">Enter it in the box below:</span>
</li> </li>
@ -1363,7 +1367,7 @@
<input id="api_button_novel" class="menu_button" type="submit" value="Connect"> <input id="api_button_novel" class="menu_button" type="submit" value="Connect">
<div id="api_loading_novel" class="api-load-icon fa-solid fa-hourglass fa-spin"></div> <div id="api_loading_novel" class="api-load-icon fa-solid fa-hourglass fa-spin"></div>
<h4><span data-i18n="Novel AI Model">Novel AI Model</span> <h4><span data-i18n="Novel AI Model">Novel AI Model</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#models" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/api-connections/novelai/#models" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</h4> </h4>
@ -1379,7 +1383,7 @@
</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 flex-container"> <div class="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>
@ -1388,15 +1392,15 @@
</span> </span>
</div> </div>
<div> <div>
<div class="flex-container"> <div class="flex-container flexFlowColumn">
<div class="flex1"> <div class="flex1">
<h4 data-i18n="Blocking API url">Blocking API url</h4> <h4 data-i18n="Blocking API url">Blocking API url</h4>
<h5>Example: http://127.0.0.1:5000/</h5> <small>Example: http://127.0.0.1:5000/</small>
<input id="textgenerationwebui_api_url_text" name="textgenerationwebui_api_url" class="text_pole wide100p" maxlength="500" value="" autocomplete="off"> <input id="textgenerationwebui_api_url_text" name="textgenerationwebui_api_url" class="text_pole wide100p" maxlength="500" value="" autocomplete="off">
</div> </div>
<div class="flex1"> <div class="flex1">
<h4 data-i18n="Streaming API url">Streaming API url</h4> <h4 data-i18n="Streaming API url">Streaming API url</h4>
<h5>Example: ws://127.0.0.1:5005/api/v1/stream</h5> <small>Example: ws://127.0.0.1:5005/api/v1/stream</small>
<input id="streaming_url_textgenerationwebui" type="text" class="text_pole wide100p" maxlength="500" value="" autocomplete="off"> <input id="streaming_url_textgenerationwebui" type="text" class="text_pole wide100p" maxlength="500" value="" autocomplete="off">
</div> </div>
</div> </div>
@ -1422,7 +1426,7 @@
<span> <span>
<ol> <ol>
<li> <li>
Follow<a href="https://docs.sillytavern.app/usage/guidebook/#api-key-1" class="notes-link" target="_blank"> these directions </a> to get your OpenAI Follow<a href="https://docs.sillytavern.app/usage/api-connections/openai/" class="notes-link" target="_blank"> these directions </a> to get your OpenAI
API key. API key.
</li> </li>
<li>Enter it in the box below:</li> <li>Enter it in the box below:</li>
@ -1521,7 +1525,7 @@
<span> <span>
<ol> <ol>
<li> <li>
Follow <a href="https://docs.sillytavern.app/usage/guidebook/#api-key-2" class="notes-link" target="_blank">these directions</a> to get your 'p-b cookie' Follow <a href="https://docs.sillytavern.app/usage/api-connections/poe/" class="notes-link" target="_blank">these directions</a> to get your 'p-b cookie'
</li> </li>
<li>Enter it in the box below:</li> <li>Enter it in the box below:</li>
</ol> </ol>
@ -1570,7 +1574,7 @@
</div> </div>
<div class="drawer-content"> <div class="drawer-content">
<h3>Advanced Formatting <h3>Advanced Formatting
<a href="https://docs.sillytavern.app/usage/guidebook/#advanced-formatting" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</h3> </h3>
@ -1616,7 +1620,7 @@
</div> </div>
<div> <div>
<h4 data-i18n="Instruct mode">Instruct mode <h4 data-i18n="Instruct mode">Instruct mode
<a href="https://docs.sillytavern.app/usage/guidebook/#instruct-mode" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/instructmode/" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</h4> </h4>
@ -1693,7 +1697,7 @@
<h4><span data-i18n="Context Formatting">Context Formatting</span></h4> <h4><span data-i18n="Context Formatting">Context Formatting</span></h4>
<div> <div>
<h4><span data-i18n="Tokenizer">Tokenizer</span> <h4><span data-i18n="Tokenizer">Tokenizer</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#tokenizer" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#tokenizer" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</h4> </h4>
@ -1709,7 +1713,7 @@
<div class="range-block"> <div class="range-block">
<div class="range-block-title justifyLeft"> <div class="range-block-title justifyLeft">
Token Padding Token Padding
<a href="https://docs.sillytavern.app/usage/guidebook/#token-padding" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#token-padding" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</div> </div>
@ -1772,7 +1776,7 @@
<div> <div>
<h4> <h4>
<span data-i18n="Multigen">Multigen</span> <span data-i18n="Multigen">Multigen</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#multigen" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#multigen" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</h4> </h4>
@ -1807,14 +1811,14 @@
<div id="WI_panel_pin_div" title="Locked = World Editor will stay open"> <div id="WI_panel_pin_div" title="Locked = World Editor will stay open">
<input type="checkbox" id="WI_panel_pin"> <input type="checkbox" id="WI_panel_pin">
<label for="WI_panel_pin"> <label for="WI_panel_pin">
<div class="unchecked fa-solid fa-lock-open "></div> <div class="unchecked fa-solid fa-unlock "></div>
<div class="checked fa-solid fa-lock "></div> <div class="checked fa-solid fa-lock "></div>
</label> </label>
</div> </div>
<div id="wi-holder"> <div id="wi-holder" class="margin5">
<h3> <h3>
World Info / Lorebooks World Info / Lorebooks
<a href="https://docs.sillytavern.app/usage/guidebook/#world-info" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</h3> </h3>
@ -1832,39 +1836,40 @@
</div> </div>
<div class="flex-container alignitemscenter"> <div class="flex-container alignitemscenter">
<div class="flex1 range-block"> <div name="WIScanAndTokens" class="flex1 flex-container flexFlowColumn">
<div class="range-block-title"> <div class="flex1 range-block">
<span data-i18n="Scan Depth">Scan Depth</span> <div class="range-block-title">
</div> <span data-i18n="Scan Depth">Scan Depth</span>
<div class="range-block-range-and-counter">
<div class="range-block-range">
<input type="range" id="world_info_depth" name="volume" min="1" max="10" step="1">
</div> </div>
<div class="range-block-counter"> <div class="range-block-range-and-counter">
<div contenteditable="true" data-for="world_info_depth" id="world_info_depth_counter"> <div class="range-block-range">
depth <input type="range" id="world_info_depth" name="volume" min="1" max="10" step="1">
</div>
<div class="range-block-counter">
<div contenteditable="true" data-for="world_info_depth" id="world_info_depth_counter">
depth
</div>
</div>
</div>
</div>
<div class="flex1 range-block">
<div class="range-block-title">
<span data-i18n="Token Budget">Token Budget</span>
</div>
<div class="range-block-range-and-counter">
<div class="range-block-range">
<input type="range" id="world_info_budget" name="volume" min="32" max="8192" step="1">
</div>
<div class="range-block-counter">
<div contenteditable="true" data-for="world_info_budget" id="world_info_budget_counter">
budget
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="range-block flex-container flexFlowColumn">
<div class="flex1 range-block">
<div class="range-block-title">
<span data-i18n="Token Budget">Token Budget</span>
</div>
<div class="range-block-range-and-counter">
<div class="range-block-range">
<input type="range" id="world_info_budget" name="volume" min="32" max="8192" step="1">
</div>
<div class="range-block-counter">
<div contenteditable="true" data-for="world_info_budget" id="world_info_budget_counter">
budget
</div>
</div>
</div>
</div>
<div class="flex1 range-block flex-container">
<label title="Entries can activate other entries by mentioning their keywords" class="checkbox_label"> <label title="Entries can activate other entries by mentioning their keywords" class="checkbox_label">
<input id="world_info_recursive" type="checkbox" /> <input id="world_info_recursive" type="checkbox" />
<span> <span>
@ -1892,7 +1897,7 @@
<div class="world_popup_logo_block"> <div class="world_popup_logo_block">
<h3> <h3>
World Info Editor World Info Editor
<a href="https://docs.sillytavern.app/usage/guidebook/#world-info-entry" class="notes-link" target="_blank"><span class="note-link-span">?</span></a> <a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/#world-info-entry" class="notes-link" target="_blank"><span class="note-link-span">?</span></a>
</h3> </h3>
</div> </div>
<div id="OpenAllWIEntries" class="menu_button fa-solid fa-expand"></div> <div id="OpenAllWIEntries" class="menu_button fa-solid fa-expand"></div>
@ -1917,7 +1922,7 @@
</div> </div>
<div id="softprompt_block"> <div id="softprompt_block">
<h4>Soft Prompt</h4> <h4>Soft Prompt</h4>
<h5>About soft prompts <a href="https://docs.sillytavern.app/usage/guidebook/#soft-prompts" class="notes-link" target="_blank"><span class="note-link-span">?</span></a></h5> <h5>About soft prompts <a href="https://docs.sillytavern.app/usage/api-connections/koboldai/#soft-prompts" class="notes-link" target="_blank"><span class="note-link-span">?</span></a></h5>
<select id="softprompt"> <select id="softprompt">
<option value="">None</option> <option value="">None</option>
</select> </select>
@ -1977,7 +1982,7 @@
<audio id="audio_message_sound" src="sounds/message.mp3" hidden></audio> <audio id="audio_message_sound" src="sounds/message.mp3" hidden></audio>
<span> <span>
<span data-i18n="Message Sound">Message Sound</span> <span data-i18n="Message Sound">Message Sound</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#message-sound" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/uicustomization/#message-sound" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</span> </span>
@ -2154,7 +2159,7 @@
<label for="render_formulas"> <label for="render_formulas">
<input id="render_formulas" type="checkbox" /> <input id="render_formulas" type="checkbox" />
<span data-i18n="Render Formulas">Render Formulas</span> <span data-i18n="Render Formulas">Render Formulas</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#formulas-rendering" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/uicustomization/#formulas-rendering" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</label> </label>
@ -2210,7 +2215,7 @@
<input id="your_name" name="your_name" placeholder="Enter your name" class="text_pole wide100p" 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 id="lock_user_name" class="menu_button fa-solid fa-user-lock" title="Click to bind your selected persona to the current chat. Click again to remove the binding."> <div id="lock_user_name" class="menu_button fa-solid fa-lock" title="Click to lock your selected persona to the current chat. Click again to remove the lock.">
</div> </div>
<div id="sync_name_button" class="menu_button fa-solid fa-sync" title="Click to set user name for all messages"> <div id="sync_name_button" class="menu_button fa-solid fa-sync" title="Click to set user name for all messages">
</div> </div>
@ -2256,17 +2261,19 @@
</div> </div>
<div id="rm_extensions_block" class="drawer-content closedDrawer"> <div id="rm_extensions_block" class="drawer-content closedDrawer">
<div class="extensions_block flex-container"> <div class="extensions_block flex-container">
<div class="alignitemscenter flex-container justify wide100p" style="justify-content: space-between;"> <div class="alignitemscenter flex-container justifyCenter wide100p" style="justify-content: space-between;">
<h3 class="margin0 flex1">Extensions API: <h3 class="margin0">Extensions API:
<a target="_blank" href="https://github.com/SillyTavern/SillyTavern-extras"> <a target="_blank" href="https://github.com/SillyTavern/SillyTavern-extras">
SillyTavern-extras SillyTavern-extras
</a> </a>
</h3> </h3>
<div id="extensions_status">Not Connected</div> <div class="flex-container">
<label for="extensions_autoconnect"> <div id="extensions_status">Not Connected</div>
<input id="extensions_autoconnect" type="checkbox"> <label for="extensions_autoconnect">
Auto-connect <input id="extensions_autoconnect" type="checkbox">
</label> Auto-connect
</label>
</div>
</div> </div>
<div class="alignitemsflexstart flex-container wide100p"> <div class="alignitemsflexstart flex-container wide100p">
<input id="extensions_url" type="text" class="flex1 heightFitContent text_pole widthNatural" maxlength="250" placeholder="Extensions URL"> <input id="extensions_url" type="text" class="flex1 heightFitContent text_pole widthNatural" maxlength="250" placeholder="Extensions URL">
@ -2293,26 +2300,38 @@
</div> </div>
</div> </div>
<nav id="right-nav-panel" class="drawer-content closedDrawer fillRight gap5px"> <nav id="right-nav-panel" class="drawer-content closedDrawer fillRight gap5px">
<div id="right-nav-panelheader" class="fa-solid fa-grip drag-grabber"></div> <div id="right-nav-panelheader" class="fa-solid fa-grip drag-grabber">
<div id="rm_PinAndTabs"> </div>
<div id="rm_button_panel_pin_div" title="Locked = Character Management panel will stay open"> <div id="CharListButtonAndHotSwaps" class="flex-container flexnowrap">
<input type="checkbox" id="rm_button_panel_pin"> <div class="flexFlowColumn flex-container">
<label for="rm_button_panel_pin"> <div id="rm_button_panel_pin_div" class="alignitemsflexstart" title="Locked = Character Management panel will stay open">
<div class="fa-solid unchecked fa-lock-open" alt=""></div> <input type="checkbox" id="rm_button_panel_pin">
<div class="fa-solid checked fa-lock" alt=""></div> <label for="rm_button_panel_pin">
</label> <div class="fa-solid unchecked fa-unlock" alt=""></div>
</div> <div class="fa-solid checked fa-lock" alt=""></div>
<div id="right-nav-panel-tabs"> </label>
</div>
<div class="right_menu_button fa-solid fa-list-ul" id="rm_button_characters" title="Select/Create Characters"></div> <div class="right_menu_button fa-solid fa-list-ul" id="rm_button_characters" title="Select/Create Characters"></div>
</div>
<div name="HotSwapWrapper" class="alignitemscenter flex-container margin0auto">
<div class="hotswap flex-container flex1"></div>
</div>
</div>
<hr>
<!-- this div structure must be preserved until group peeking can adjust -->
<div id="rm_PinAndTabs">
<div id="right-nav-panel-tabs" class="">
<div id="rm_button_selected_ch"> <div id="rm_button_selected_ch">
<h2></h2> <h2></h2>
</div> </div>
</div> </div>
</div> </div>
<!-- end group peeking cope structure-->
<div class="hotswap flex-container justifyCenter">
</div>
<div name="Solo Char Create/Edit Panel" id="rm_ch_create_block" class="right_menu flex-container flexFlowColumn" style="display: none;"> <div name="Solo Char Create/Edit Panel" id="rm_ch_create_block" class="right_menu flex-container flexFlowColumn" style="display: none;">
<form id="form_create" action="javascript:void(null);" method="post" enctype="multipart/form-data"> <form id="form_create" action="javascript:void(null);" method="post" enctype="multipart/form-data">
@ -2322,28 +2341,31 @@
<input id="character_name_pole" name="ch_name" class="text_pole" placeholder="Name this character" maxlength="50" value="" autocomplete="off"> <input id="character_name_pole" name="ch_name" class="text_pole" placeholder="Name this character" maxlength="50" value="" autocomplete="off">
</div> </div>
<div id="avatar_div" class="avatar_div"> <div id="avatar_div" class="avatar_div alignitemsflexstart justifySpaceBetween">
<div id="avatar_div_div" class="avatar"> <div id="avatar_div_div" class="avatar">
<img id="avatar_load_preview" src="img/ai4.png" alt="avatar"> <img id="avatar_load_preview" src="img/ai4.png" alt="avatar">
</div> </div>
<div class="form_create_bottom_buttons_block"> <div class="flex-container flexFlowColumn">
<label for="add_avatar_button" class="menu_button fa-solid fa-file-image " title="Click to select a new avatar for this character"> <div class="form_create_bottom_buttons_block">
<input type="file" id="add_avatar_button" name="avatar" accept="image/png, image/jpeg, image/jpg, image/gif, image/bmp"> <label for="add_avatar_button" class="menu_button fa-solid fa-file-image " title="Click to select a new avatar for this character">
</label> <input type="file" id="add_avatar_button" name="avatar" accept="image/png, image/jpeg, image/jpg, image/gif, image/bmp">
<div id="rm_button_back" class="menu_button fa-solid fa-left-long "></div> </label>
<div id="renameCharButton" class="menu_button fa-solid fa-user-pen" title="Rename Character"></div> <div id="rm_button_back" class="menu_button fa-solid fa-left-long "></div>
<div id="favorite_button" class="menu_button fa-solid fa-star" title="Add to Favorites"></div> <div id="renameCharButton" class="menu_button fa-solid fa-user-pen" title="Rename Character"></div>
<input type="hidden" id="fav_checkbox" name="fav" /> <div id="favorite_button" class="menu_button fa-solid fa-star" title="Add to Favorites"></div>
<div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions"></div> <input type="hidden" id="fav_checkbox" name="fav" />
<div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download"></div> <div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions"></div>
<div id="dupe_button" class="menu_button fa-solid fa-clone " title="Duplicate Character"></div> <div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download"></div>
<label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character"> <div id="dupe_button" class="menu_button fa-solid fa-clone " title="Duplicate Character"></div>
<input type="submit" id="create_button" name="create_button"> <label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character">
</label> <input type="submit" id="create_button" name="create_button">
<div id="delete_button" class="menu_button fa-solid fa-skull " title="Delete Character"></div> </label>
<div id="delete_button" class="menu_button fa-solid fa-skull " title="Delete Character"></div>
</div>
<div id="result_info" class="justifyCenter flex-container" title="Token counts may be inaccurate and provided just for reference.">&nbsp;</div>
</div> </div>
</div> </div>
<div title="Token counts may be inaccurate and provided just for reference." id="result_info">&nbsp;</div>
</div> </div>
<hr> <hr>
@ -2357,7 +2379,7 @@
<div id="description_div" class="marginBot5"> <div id="description_div" class="marginBot5">
<span data-i18n="Description">Description</span> <span data-i18n="Description">Description</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#character-description" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#character-description" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</div> </div>
@ -2367,7 +2389,7 @@
<div id="first_message_div" class="marginBot5 title_restorable"> <div id="first_message_div" class="marginBot5 title_restorable">
<span> <span>
<span data-i18n="First message">First message</span> <span data-i18n="First message">First message</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#first-message" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#first-message" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</span> </span>
@ -2412,7 +2434,7 @@
<div class=""> <div class="">
<div class="flex-container flexnowrap width100p whitespacenowrap"> <div class="flex-container flexnowrap width100p whitespacenowrap">
<span data-i18n="Group reply strategy">Group reply strategy</span> <span data-i18n="Group reply strategy">Group reply strategy</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#group-chats" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/groupchats/" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</div> </div>
@ -2597,7 +2619,7 @@
<div id="personality_div"> <div id="personality_div">
<h4> <h4>
<span data-i18n="Personality summary">Personality summary</span> <span data-i18n="Personality summary">Personality summary</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#personality-summary" class="notes-link" target="_blank"><span class="note-link-span">?</span></a> <a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#personality-summary" class="notes-link" target="_blank"><span class="note-link-span">?</span></a>
</h4> </h4>
<textarea id="personality_textarea" name="personality" placeholder="(A brief description of the personality)" form="form_create" class="text_pole" autocomplete="off" rows="1" maxlength="20000"></textarea> <textarea id="personality_textarea" name="personality" placeholder="(A brief description of the personality)" form="form_create" class="text_pole" autocomplete="off" rows="1" maxlength="20000"></textarea>
</div> </div>
@ -2605,7 +2627,7 @@
<div id="scenario_div"> <div id="scenario_div">
<h4> <h4>
<span data-i18n="Scenario">Scenario</span> <span data-i18n="Scenario">Scenario</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#scenario" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#scenario" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
</h4> </h4>
@ -2627,7 +2649,7 @@
<div id="mes_example_div" class="flex-container flexFlowColumn"> <div id="mes_example_div" class="flex-container flexFlowColumn">
<div> <div>
<h4><span data-i18n="Examples of dialogue">Examples of dialogue</span></h4> <h4><span data-i18n="Examples of dialogue">Examples of dialogue</span></h4>
<h5>Important to set the character's writing style. <a href="https://docs.sillytavern.app/usage/guidebook/#examples-of-dialogue" class="notes-link" target="_blank"><span class="note-link-span">?</span></a></h5> <h5>Important to set the character's writing style. <a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#examples-of-dialogue" class="notes-link" target="_blank"><span class="note-link-span">?</span></a></h5>
</div> </div>
<textarea id="mes_example_textarea" class="flexGrow" name="mes_example" placeholder="(Examples of chat dialog. Begin each example with <start> on a new line.)" form="form_create" maxlength="20000" rows="6"></textarea> <textarea id="mes_example_textarea" class="flexGrow" name="mes_example" placeholder="(Examples of chat dialog. Begin each example with <start> on a new line.)" form="form_create" maxlength="20000" rows="6"></textarea>
</div> </div>
@ -2643,7 +2665,7 @@
<span id="ChatHistoryCharName"></span> <span id="ChatHistoryCharName"></span>
<br> <br>
<span data-i18n="Chat History">Chat History</span> <span data-i18n="Chat History">Chat History</span>
<a href="https://docs.sillytavern.app/usage/guidebook/#chat-import" class="notes-link" target="_blank"><span class="note-link-span">?</span></a> <a href="https://docs.sillytavern.app/usage/core-concepts/chatfilemanagement/#chat-import" class="notes-link" target="_blank"><span class="note-link-span">?</span></a>
</div> </div>
<form id="form_import_chat" action="javascript:void(null);" method="post" enctype="multipart/form-data" style="display: none;"> <form id="form_import_chat" action="javascript:void(null);" method="post" enctype="multipart/form-data" style="display: none;">
<input type="file" id="chat_import_file" accept=".json, .jsonl" name="avatar"> <input type="file" id="chat_import_file" accept=".json, .jsonl" name="avatar">
@ -2777,11 +2799,11 @@
<form class="world_entry_form"> <form class="world_entry_form">
<div class="inline-drawer wide100p"> <div class="inline-drawer wide100p">
<div class="inline-drawer-toggle inline-drawer-header"> <div class="inline-drawer-toggle inline-drawer-header">
<div class="world_entry_thin_controls wide100p"> <div class="gap5px world_entry_thin_controls wide100p">
<div class="world_entry_form_control"> <div class="world_entry_form_control">
<label for="key"> <label for="key">
<h4><span data-i18n="Keywords">Keywords</span></h4> <h4><span data-i18n="Keywords">Keywords</span></h4>
<h5><span data-i18n="Separate with commas">Separate with commas</span></h5> <small><span data-i18n="Separate with commas">Separate with commas</span></small>
</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>
@ -2789,20 +2811,20 @@
<label for="keysecondary"> <label for="keysecondary">
<h4><span data-i18n="Secondary Required Keywords">Secondary Required Keywords</span> <h4><span data-i18n="Secondary Required Keywords">Secondary Required Keywords</span>
</h4> </h4>
<h5><span data-i18n="Separate with commas">Separate with commas</span></h5> <small><span data-i18n="Separate with commas">Separate with commas</span></small>
</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>
</div> </div>
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
</div> </div>
<div class="inline-drawer-content"> <div class="inline-drawer-content flex-container">
<div class="world_entry_thin_controls wide100p"> <div class="world_entry_thin_controls wide100p">
<div class="world_entry_form_control"> <div class="world_entry_form_control">
<label for="content "> <label for="content ">
<h4><span data-i18n="Content">Content</span></h4> <h4><span data-i18n="Content">Content</span></h4>
<h5><span data-i18n="What this keyword should mean to the AI">What this keyword <small><span data-i18n="What this keyword should mean to the AI">What this keyword
should mean to the AI</span></h5> should mean to the AI</span></small>
</label> </label>
<textarea class="text_pole" name="content" rows="4" placeholder=""></textarea> <textarea class="text_pole" name="content" rows="4" placeholder=""></textarea>
</div> </div>
@ -2812,15 +2834,13 @@
<div class="world_entry_form_control"> <div class="world_entry_form_control">
<label for="comment"> <label for="comment">
<h4><span data-i18n="Memo/Note">Memo/Note</span></h4> <h4><span data-i18n="Memo/Note">Memo/Note</span></h4>
<h5><span data-i18n="Not sent to AI">Not sent to AI</span></h5> <small><span data-i18n="Not sent to AI">Not sent to AI</span></small>
</label> </label>
<textarea class="text_pole" rows="1" name="comment" maxlength="250"></textarea> <textarea class="text_pole" rows="1" name="comment" maxlength="250"></textarea>
</div> </div>
</div> </div>
<div class="flex-container flex1 justifySpaceBetween world_entry_form_horizontal">
<div class="flex-container flexFlowColumn flexNoGap wi-enter-footer-text ">
<div class="world_entry_form_control world_entry_form_horizontal">
<div class="flex-container flexFlowColumn flexNoGap wi-enter-footer-text flex1 ">
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" name="constant" /> <input type="checkbox" name="constant" />
<span data-i18n="Constant">Constant</span> <span data-i18n="Constant">Constant</span>
@ -2830,7 +2850,7 @@
<span data-i18n="Selective">Selective</span> <span data-i18n="Selective">Selective</span>
</label> </label>
</div> </div>
<div class="world_entry_form_control world_entry_form_radios wi-enter-footer-text flex1"> <div class="world_entry_form_control world_entry_form_radios wi-enter-footer-text ">
<div> <div>
<label><input type="radio" name="position" value="0"> <label><input type="radio" name="position" value="0">
<span data-i18n="Before Char">Before Char</span> <span data-i18n="Before Char">Before Char</span>
@ -2842,19 +2862,13 @@
</label> </label>
</div> </div>
</div> </div>
<div class="world_entry_form_control wi-enter-footer-text flex1 flex-container flexNoGap "> <div class="world_entry_form_control wi-enter-footer-text flex-container flexNoGap ">
<!-- world_entry_form_control -->
<!-- <label for="order"> -->
Insertion Order Insertion Order
<!-- Bigger number = inserted earlier --> <input class="text_pole wideMax100px" type="number" name="order" placeholder="" />
<!-- </label> -->
<input class="text_pole" type="number" name="order" placeholder="" />
</div> </div>
<div class="flex-container flexFlowColumn flexNoGap wi-enter-footer-text flex1"> <div class="flex-container flexFlowColumn flexNoGap wi-enter-footer-text ">
<div class="world_entry_form_uid"> <div class="world_entry_form_uid">
UID: UID:
&nbsp; &nbsp;
@ -2866,13 +2880,12 @@
<span class="world_entry_form_token_counter">0</span> <span class="world_entry_form_token_counter">0</span>
</div> </div>
</div> </div>
<div> <div class="wi-enter-footer-text">
<label class="checkbox"> <label class="checkbox flex-container alignitemscenter">
<input type="checkbox" name="disable" /> <input type="checkbox" name="disable" />
<span data-i18n="Disable">Disable</span> <span data-i18n="Disable">Disable</span>
</label> </label>
</div> </div>
<span class="world_popup_expander">&nbsp;</span>
<input class="menu_button delete_entry_button" type="submit" value="Delete Entry" /> <input class="menu_button delete_entry_button" type="submit" value="Delete Entry" />
</div> </div>
</div> </div>
@ -3138,10 +3151,19 @@
<div imgfile="" class="avatar"> <div imgfile="" class="avatar">
<img src="" alt="User Avatar"> <img src="" alt="User Avatar">
</div> </div>
<div class="avatar-buttons"> <div class="avatar-buttons avatar-buttons-top">
<button class="menu_button bind_user_name" title="Bind user name to that avatar"> <button class="menu_button bind_user_name" title="Bind user name to that avatar">
<i class="fa-solid fa-user-edit"></i> <i class="fa-solid fa-user-edit"></i>
</button> </button>
<button class="menu_button set_default_persona" title="Select this as default persona for the new chats.">
<i class="fa-solid fa-crown"></i>
</button>
</div>
<div class="avatar-buttons avatar-buttons-bottom">
<button class="menu_button set_user_info" title="Under construction">
<i class="fa-solid fa-circle-user"></i>
</button>
<button class="menu_button delete_avatar" title="Delete persona"> <button class="menu_button delete_avatar" title="Delete persona">
<i class="fa-solid fa-trash-alt"></i> <i class="fa-solid fa-trash-alt"></i>
</button> </button>

View File

@ -1464,6 +1464,7 @@ function sendSystemMessage(type, text, extra = {}) {
if (type == system_message_types.HELP) { if (type == system_message_types.HELP) {
newMessage.mes += getSlashCommandsHelp(); newMessage.mes += getSlashCommandsHelp();
newMessage.mes += `<br><b>Still got questions left? The <a target="_blank" href="https://docs.sillytavern.app/">Official SillyTavern Documentation Website</a> has much more information!</b>`;
} }
if (!newMessage.extra) { if (!newMessage.extra) {
@ -3928,8 +3929,11 @@ function appendUserAvatar(name) {
const personaName = power_user.personas[name]; const personaName = power_user.personas[name];
if (personaName) { if (personaName) {
template.attr('title', personaName); template.attr('title', personaName);
} else {
template.attr('title', '[Unnamed Persona]');
} }
template.find('.avatar').attr('imgfile', name); template.find('.avatar').attr('imgfile', name);
template.toggleClass('default_persona', name === power_user.default_persona)
template.find('img').attr('src', `User Avatars/${name}`); template.find('img').attr('src', `User Avatars/${name}`);
$("#user_avatar_block").append(template); $("#user_avatar_block").append(template);
highlightSelectedAvatar(); highlightSelectedAvatar();
@ -3950,9 +3954,9 @@ export function setUserName(value) {
name1 = value; name1 = value;
if (name1 === undefined || name1 == "") if (name1 === undefined || name1 == "")
name1 = default_user_name; name1 = default_user_name;
console.log(name1); console.log(`User name changed to ${name1}`);
$("#your_name").val(name1); $("#your_name").val(name1);
toastr.success(`Your messages will now be sent as ${name1}`, 'User Name updated'); toastr.success(`Your messages will now be sent as ${name1}`, 'Current persona updated');
saveSettings("change_name"); saveSettings("change_name");
} else { } else {
toastr.warning('You cannot change your name while sending a message', 'Warning'); toastr.warning('You cannot change your name while sending a message', 'Warning');
@ -3962,6 +3966,7 @@ export function setUserName(value) {
export function autoSelectPersona(name) { export function autoSelectPersona(name) {
for (const [key, value] of Object.entries(power_user.personas)) { for (const [key, value] of Object.entries(power_user.personas)) {
if (value === name) { if (value === name) {
console.log(`Auto-selecting persona ${key} for name ${name}`);
$(`.avatar[imgfile="${key}"]`).trigger('click'); $(`.avatar[imgfile="${key}"]`).trigger('click');
return; return;
} }
@ -3978,15 +3983,38 @@ async function bindUserNameToPersona() {
const existingPersona = power_user.personas[avatarId]; const existingPersona = power_user.personas[avatarId];
const personaName = await callPopup('<h3>Enter a name for this persona:</h3>(If empty name is provided, this will unbind the name from this avatar)', 'input', existingPersona || ''); const personaName = await callPopup('<h3>Enter a name for this persona:</h3>(If empty name is provided, this will unbind the name from this avatar)', 'input', existingPersona || '');
if (personaName) {
// If the user clicked cancel, don't do anything
if (personaName === false) {
return;
}
if (personaName.length > 0) {
// If the user clicked ok and entered a name, bind the name to the persona
console.log(`Binding persona ${avatarId} to name ${personaName}`);
power_user.personas[avatarId] = personaName; power_user.personas[avatarId] = personaName;
// If the user is currently using this persona, update the name
if (avatarId === user_avatar) {
console.log(`Auto-updating user name to ${personaName}`);
setUserName(personaName);
}
} else { } else {
// If the user clicked ok, but didn't enter a name, delete the persona
console.log(`Unbinding persona ${avatarId}`);
delete power_user.personas[avatarId]; delete power_user.personas[avatarId];
} }
saveSettingsDebounced(); saveSettingsDebounced();
await getUserAvatars(); await getUserAvatars();
} }
function updateUserLockIcon() {
const hasLock = !!chat_metadata['persona'];
$('#lock_user_name').toggleClass('fa-lock', !hasLock);
$('#lock_user_name').toggleClass('fa-unlock', hasLock);
}
function setUserAvatar() { function setUserAvatar() {
user_avatar = $(this).attr("imgfile"); user_avatar = $(this).attr("imgfile");
reloadUserAvatar(); reloadUserAvatar();
@ -3997,10 +4025,10 @@ function setUserAvatar() {
if (personaName && name1 !== personaName) { if (personaName && name1 !== personaName) {
const lockedPersona = chat_metadata['persona']; const lockedPersona = chat_metadata['persona'];
if (lockedPersona && lockedPersona !== user_avatar) { if (lockedPersona && lockedPersona !== user_avatar) {
toastr.warning( toastr.info(
'Click the "Lock" to bind again. Otherwise, the selection will be reset when your reload the chat.', `To permanently set "${personaName}" as the selected persona, unlock and relock it using the "Lock" button. Otherwise, the selection resets upon reloading the chat.`,
`This chat is locked to a different persona (${power_user.personas[lockedPersona]}).`, `This chat is locked to a different persona (${power_user.personas[lockedPersona]}).`,
{ timeOut: 10000, extendedTimeOut: 20000 }, { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true },
); );
} }
@ -4008,6 +4036,57 @@ function setUserAvatar() {
} }
} }
async function setUserInfo() {
// TODO Replace with actual implementation
callPopup('This functionality is under development.<br>Please check back later.', 'text');
}
async function setDefaultPersona() {
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
if (!avatarId) {
console.warn('No avatar id found');
return;
}
const currentDefault = power_user.default_persona;
if (power_user.personas[avatarId] === undefined) {
console.warn(`No persona name found for avatar ${avatarId}`);
toastr.warning('You must bind a name to this persona before you can set it as the default.', 'Persona name not set');
return;
}
const personaName = power_user.personas[avatarId];
if (avatarId === currentDefault) {
const confirm = await callPopup('Are you sure you want to remove the default persona?', 'confirm');
if (!confirm) {
console.debug('User cancelled removing default persona');
return;
}
console.log(`Removing default persona ${avatarId}`);
toastr.info('This persona will no longer be used by default when you open a new chat.', `Default persona removed`);
delete power_user.default_persona;
} else {
const confirm = await callPopup(`<h3>Are you sure you want to set "${personaName}" as the default persona?</h3>
This name and avatar will be used for all new chats, as well as existing chats where the user persona is not locked.`, 'confirm');
if (!confirm) {
console.debug('User cancelled setting default persona');
return;
}
power_user.default_persona = avatarId;
toastr.success('This persona will be used by default when you open a new chat.', `Default persona set to ${personaName}`);
}
saveSettingsDebounced();
await getUserAvatars();
}
async function deleteUserAvatar() { async function deleteUserAvatar() {
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile'); const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
@ -4017,6 +4096,7 @@ async function deleteUserAvatar() {
} }
if (avatarId == user_avatar) { if (avatarId == user_avatar) {
console.warn(`User tried to delete their current avatar ${avatarId}`);
toastr.warning('You cannot delete the avatar you are currently using', 'Warning'); toastr.warning('You cannot delete the avatar you are currently using', 'Warning');
return; return;
} }
@ -4024,6 +4104,7 @@ async function deleteUserAvatar() {
const confirm = await callPopup('Are you sure you want to delete this avatar?', 'confirm'); const confirm = await callPopup('Are you sure you want to delete this avatar?', 'confirm');
if (!confirm) { if (!confirm) {
console.debug('User cancelled deleting avatar');
return; return;
} }
@ -4036,46 +4117,96 @@ async function deleteUserAvatar() {
}); });
if (request.ok) { if (request.ok) {
console.log(`Deleted avatar ${avatarId}`);
delete power_user.personas[avatarId]; delete power_user.personas[avatarId];
if (avatarId === power_user.default_persona) {
toastr.warning('The default persona was deleted. You will need to set a new default persona.', 'Default persona deleted');
power_user.default_persona = null;
}
if (avatarId === chat_metadata['persona']) {
toastr.warning('The locked persona was deleted. You will need to set a new persona for this chat.', 'Persona deleted');
delete chat_metadata['persona'];
saveMetadata();
}
saveSettingsDebounced(); saveSettingsDebounced();
await getUserAvatars(); await getUserAvatars();
updateUserLockIcon();
} }
} }
function lockUserNameToChat() { function lockUserNameToChat() {
if (chat_metadata['persona']) { if (chat_metadata['persona']) {
console.log(`Unlocking persona for this chat ${chat_metadata['persona']}`);
delete chat_metadata['persona']; delete chat_metadata['persona'];
saveMetadata(); saveMetadata();
toastr.info('User persona is now unlocked for this chat. Click the "Lock" to bind again.', 'Persona unlocked'); toastr.info('User persona is now unlocked for this chat. Click the "Lock" again to revert.', 'Persona unlocked');
updateUserLockIcon();
return; return;
} }
if (!(user_avatar in power_user.personas)) { if (!(user_avatar in power_user.personas)) {
toastr.info('Creating a new persona for currently selected user name and avatar...', 'Persona not set for this avatar'); console.log(`Creating a new persona ${user_avatar}`);
toastr.info(
'Creating a new persona for currently selected user name and avatar...',
'Persona not set for this avatar',
{ timeOut: 10000, extendedTimeOut: 20000, },
);
power_user.personas[user_avatar] = name1; power_user.personas[user_avatar] = name1;
} }
chat_metadata['persona'] = user_avatar; chat_metadata['persona'] = user_avatar;
saveMetadata(); saveMetadata();
saveSettingsDebounced(); saveSettingsDebounced();
console.log(`Locking persona for this chat ${user_avatar}`);
toastr.success(`User persona is locked to ${name1} in this chat`); toastr.success(`User persona is locked to ${name1} in this chat`);
updateUserLockIcon();
} }
eventSource.on(event_types.CHAT_CHANGED, () => { eventSource.on(event_types.CHAT_CHANGED, () => {
// If persona is locked, select it // Define a persona for this chat
let chatPersona = '';
if (chat_metadata['persona']) { if (chat_metadata['persona']) {
// Find the avatar file // If persona is locked in chat metadata, select it
const personaAvatar = $(`.avatar[imgfile="${chat_metadata['persona']}"]`).trigger('click'); console.log(`Using locked persona ${chat_metadata['persona']}`);
chatPersona = chat_metadata['persona'];
// Avatar missing (persona deleted) } else if (power_user.default_persona) {
if (personaAvatar.length == 0) { // If default persona is set, select it
console.warn('Persona avatar not found, unlocking persona'); console.log(`Using default persona ${power_user.default_persona}`);
delete chat_metadata['persona']; chatPersona = power_user.default_persona;
return;
}
personaAvatar.trigger('click');
} }
// No persona set: user current settings
if (!chatPersona) {
console.debug('No default or locked persona set for this chat');
return;
}
// Find the avatar file
const personaAvatar = $(`.avatar[imgfile="${chatPersona}"]`).trigger('click');
// Avatar missing (persona deleted)
if (chat_metadata['persona'] && personaAvatar.length == 0) {
console.warn('Persona avatar not found, unlocking persona');
delete chat_metadata['persona'];
updateUserLockIcon();
return;
}
// Default persona missing
if (power_user.default_persona && personaAvatar.length == 0) {
console.warn('Default persona avatar not found, clearing default persona');
power_user.default_persona = null;
saveSettingsDebounced();
return;
}
// Persona avatar found, select it
personaAvatar.trigger('click');
updateUserLockIcon();
}); });
//***************SETTINGS****************// //***************SETTINGS****************//
@ -5024,7 +5155,7 @@ async function deleteMessageImage() {
mesBlock.find('.mes_img_container').removeClass('img_extra'); mesBlock.find('.mes_img_container').removeClass('img_extra');
mesBlock.find('.mes_img').attr('src', ''); mesBlock.find('.mes_img').attr('src', '');
saveChatConditional(); saveChatConditional();
updateVisibleDivs('#chat', false); /*updateVisibleDivs('#chat', false);*/
} }
function enlargeMessageImage() { function enlargeMessageImage() {
@ -5704,9 +5835,10 @@ $(document).ready(function () {
updateVisibleDivs('#rm_print_characters_block', true); updateVisibleDivs('#rm_print_characters_block', true);
}, 5)); }, 5));
$("#chat").on('scroll', debounce(() => { // This does not actually increase performance.
/*$("#chat").on('scroll', debounce(() => {
updateVisibleDivs('#chat', false); updateVisibleDivs('#chat', false);
}, 10)); }, 10));*/
let S_TAFocused = false; let S_TAFocused = false;
let S_TAPreviouslyFocused = false; let S_TAPreviouslyFocused = false;
@ -6958,6 +7090,8 @@ $(document).ready(function () {
$(document).on('click', '.bind_user_name', bindUserNameToPersona); $(document).on('click', '.bind_user_name', bindUserNameToPersona);
$(document).on('click', '.delete_avatar', deleteUserAvatar); $(document).on('click', '.delete_avatar', deleteUserAvatar);
$(document).on('click', '.set_default_persona', setDefaultPersona);
$(document).on('click', '.set_user_info', setUserInfo);
$('#lock_user_name').on('click', lockUserNameToChat); $('#lock_user_name').on('click', lockUserNameToChat);
//**************************CHARACTER IMPORT EXPORT*************************// //**************************CHARACTER IMPORT EXPORT*************************//

View File

@ -260,16 +260,23 @@ export function RA_CountCharTokens() {
(power_user.pin_examples ? characters[this_chid].mes_example : ''), (power_user.pin_examples ? characters[this_chid].mes_example : ''),
].join('\n').replace(/\r/gm, '').trim(); ].join('\n').replace(/\r/gm, '').trim();
perm_tokens = getTokenCount(perm_string); perm_tokens = getTokenCount(perm_string);
} else { console.debug("RA_TC -- no valid char found, closing."); } // if neither, probably safety char or some error in loading // if neither, probably safety char or some error in loading
} else { console.debug("RA_TC -- no valid char found, closing."); }
} }
// display the counted tokens // display the counted tokens
if (count_tokens < 1024 && perm_tokens < 1024) { if (count_tokens < 1024 && perm_tokens < 1024) {
$("#result_info").html(count_tokens + " Tokens (" + perm_tokens + " Permanent)"); //display normal if both counts are under 1024 //display normal if both counts are under 1024
$("#result_info").html(`<small>${count_tokens} Tokens (${perm_tokens} Permanent)</small>`);
} else { } else {
$("#result_info").html(` $("#result_info").html(`
<span class="neutral_warning">${count_tokens}</span>&nbsp;Tokens (<span class="neutral_warning">${perm_tokens}</span><span>&nbsp;Permanent Tokens) <div class="flex-container flexFlowColumn alignitemscenter">
<br> <div class="flex-container flexnowrap flexNoGap">
<div id="chartokenwarning" class="menu_button whitespacenowrap"><a href="https://docs.sillytavern.app/usage/guidebook/#character-tokens" target="_blank">Learn More About Token 'Limits'</a></div>`); <small class="flex-container flexnowrap flexNoGap">
<div class="neutral_warning">${count_tokens}</div>&nbsp;Tokens (<div class="neutral_warning">${perm_tokens}</div><div>&nbsp;Permanent)</div>
</small>
</div>
<div id="chartokenwarning" class="menu_button whitespacenowrap"><a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#character-tokens" target="_blank">About Token 'Limits'</a></div>
</div>`);
} //warn if either are over 1024 } //warn if either are over 1024
} }
//Auto Load Last Charcter -- (fires when active_character is defined and auto_load_chat is true) //Auto Load Last Charcter -- (fires when active_character is defined and auto_load_chat is true)

View File

@ -1,4 +1,4 @@
import { callPopup, eventSource, event_types, extension_prompt_types, saveSettings, saveSettingsDebounced } from "../script.js"; import { callPopup, eventSource, event_types, saveSettings, saveSettingsDebounced } from "../script.js";
import { isSubsetOf, debounce } from "./utils.js"; import { isSubsetOf, debounce } from "./utils.js";
export { export {
getContext, getContext,
@ -69,6 +69,20 @@ const getContext = () => window['SillyTavern'].getContext();
const getApiUrl = () => extension_settings.apiUrl; const getApiUrl = () => extension_settings.apiUrl;
let connectedToApi = false; let connectedToApi = false;
function showHideExtensionsMenu() {
const hasMenuItems = $('#extensionsMenu').children().length > 0;
// We have menu items, so we can stop checking
if (hasMenuItems) {
clearInterval(menuInterval);
}
$('#extensionsMenuButton').toggle(hasMenuItems);
}
// Periodically check for new extensions
const menuInterval = setInterval(showHideExtensionsMenu, 1000);
async function doExtrasFetch(endpoint, args) { async function doExtrasFetch(endpoint, args) {
if (!args) { if (!args) {
args = {} args = {}
@ -219,7 +233,7 @@ function autoConnectInputHandler() {
function addExtensionsButtonAndMenu() { function addExtensionsButtonAndMenu() {
const buttonHTML = const buttonHTML =
`<div id="extensionsMenuButton" class="fa-solid fa-magic-wand-sparkles" title="Extras Extensions" /></div>`; `<div id="extensionsMenuButton" style="display: none;" class="fa-solid fa-magic-wand-sparkles" title="Extras Extensions" /></div>`;
const extensionsMenuHTML = `<div id="extensionsMenu" class="options-content" style="display: none;"></div>`; const extensionsMenuHTML = `<div id="extensionsMenu" class="options-content" style="display: none;"></div>`;
$(document.body).append(extensionsMenuHTML); $(document.body).append(extensionsMenuHTML);

View File

@ -166,5 +166,5 @@ $(document).ready(function () {
setInterval(moduleWorker, UPDATE_INTERVAL); setInterval(moduleWorker, UPDATE_INTERVAL);
registerSlashCommand('lock', onLockBackgroundClick, [], " locks a background for the currently selected chat", true, true); registerSlashCommand('lock', onLockBackgroundClick, [], " locks a background for the currently selected chat", true, true);
registerSlashCommand('unlock', onUnlockBackgroundClick, [], ' unlocks a background for the currently selected chat', true, true); registerSlashCommand('unlock', onUnlockBackgroundClick, [], ' unlocks a background for the currently selected chat', true, true);
registerSlashCommand('autobg', autoBackgroundCommand, ['bgauto'], ' automatically changes the background based on the chat context', true, true); registerSlashCommand('autobg', autoBackgroundCommand, ['bgauto'], ' automatically changes the background based on the chat context using the AI request prompt', true, true);
}); });

View File

@ -59,7 +59,7 @@ function addDiceRollButton() {
button.hide(); button.hide();
let popper = Popper.createPopper(button.get(0), dropdown.get(0), { let popper = Popper.createPopper(button.get(0), dropdown.get(0), {
placement: 'bottom', placement: 'top',
}); });
$(document).on('click touchend', function (e) { $(document).on('click touchend', function (e) {
@ -68,10 +68,10 @@ function addDiceRollButton() {
if (target.is(button) && !dropdown.is(":visible")) { if (target.is(button) && !dropdown.is(":visible")) {
e.preventDefault(); e.preventDefault();
dropdown.show(200); dropdown.fadeIn(250);
popper.update(); popper.update();
} else { } else {
dropdown.hide(200); dropdown.fadeOut(250);
} }
}); });
} }

View File

@ -1,4 +1,11 @@
import { chat_metadata, saveSettingsDebounced, this_chid } from "../../../script.js"; import {
chat_metadata,
eventSource,
event_types,
getTokenCount,
saveSettingsDebounced,
this_chid,
} from "../../../script.js";
import { selected_group } from "../../group-chats.js"; import { selected_group } from "../../group-chats.js";
import { ModuleWorkerWrapper, extension_settings, getContext, saveMetadataDebounced } from "../../extensions.js"; import { ModuleWorkerWrapper, extension_settings, getContext, saveMetadataDebounced } from "../../extensions.js";
import { registerSlashCommand } from "../../slash-commands.js"; import { registerSlashCommand } from "../../slash-commands.js";
@ -66,6 +73,7 @@ function setNotePositionCommand(_, text) {
async function onExtensionFloatingPromptInput() { async function onExtensionFloatingPromptInput() {
chat_metadata[metadata_keys.prompt] = $(this).val(); chat_metadata[metadata_keys.prompt] = $(this).val();
$('#extension_floating_prompt_token_counter').text(getTokenCount(chat_metadata[metadata_keys.prompt]));
saveMetadataDebounced(); saveMetadataDebounced();
} }
@ -93,6 +101,7 @@ async function onExtensionFloatingPositionInput(e) {
function onExtensionFloatingDefaultInput() { function onExtensionFloatingDefaultInput() {
extension_settings.note.default = $(this).val(); extension_settings.note.default = $(this).val();
$('#extension_floating_default_token_counter').text(getTokenCount(extension_settings.note.default));
saveSettingsDebounced(); saveSettingsDebounced();
} }
@ -173,6 +182,13 @@ function onANMenuItemClick() {
} }
} }
function onChatChanged() {
const tokenCounter1 = chat_metadata[metadata_keys.prompt] ? getTokenCount(chat_metadata[metadata_keys.prompt]) : 0;
const tokenCounter2 = extension_settings.note.default ? getTokenCount(extension_settings.note.default) : 0;
$('#extension_floating_prompt_token_counter').text(tokenCounter1);
$('#extension_floating_default_token_counter').text(tokenCounter2);
}
(function () { (function () {
function addExtensionsSettings() { function addExtensionsSettings() {
const settingsHtml = ` const settingsHtml = `
@ -195,6 +211,7 @@ function onANMenuItemClick() {
</small> </small>
<textarea id="extension_floating_prompt" class="text_pole" rows="8" maxlength="10000"></textarea> <textarea id="extension_floating_prompt" class="text_pole" rows="8" maxlength="10000"></textarea>
<div class="extension_token_counter">Tokens: <span id="extension_floating_prompt_token_counter">0</small></div>
<div class="floating_prompt_radio_group"> <div class="floating_prompt_radio_group">
<label> <label>
@ -228,6 +245,7 @@ function onANMenuItemClick() {
<textarea id="extension_floating_default" class="text_pole" rows="8" maxlength="10000" <textarea id="extension_floating_default" class="text_pole" rows="8" maxlength="10000"
placeholder="Example:\n[Scenario: wacky adventures; Genre: romantic comedy; Style: verbose, creative]"></textarea> placeholder="Example:\n[Scenario: wacky adventures; Genre: romantic comedy; Style: verbose, creative]"></textarea>
<div class="extension_token_counter">Tokens: <span id="extension_floating_default_token_counter">0</small></div>
</div> </div>
</div> </div>
</div> </div>
@ -265,4 +283,5 @@ function onANMenuItemClick() {
registerSlashCommand('depth', setNoteDepthCommand, [], "<span class='monospace'>(number)</span> sets an author's note depth for in-chat positioning", true, true); registerSlashCommand('depth', setNoteDepthCommand, [], "<span class='monospace'>(number)</span> sets an author's note depth for in-chat positioning", true, true);
registerSlashCommand('freq', setNoteIntervalCommand, ['interval'], "<span class='monospace'>(number)</span> sets an author's note insertion frequency", true, true); registerSlashCommand('freq', setNoteIntervalCommand, ['interval'], "<span class='monospace'>(number)</span> sets an author's note insertion frequency", true, true);
registerSlashCommand('pos', setNotePositionCommand, ['position'], "(<span class='monospace'>chat</span> or <span class='monospace'>scenario</span>) sets an author's note position", true, true); registerSlashCommand('pos', setNotePositionCommand, ['position'], "(<span class='monospace'>chat</span> or <span class='monospace'>scenario</span>) sets an author's note position", true, true);
eventSource.on(event_types.CHAT_CHANGED, onChatChanged);
})(); })();

View File

@ -1,61 +1,67 @@
#floatingPrompt { #floatingPrompt {
overflow-y: auto; overflow-y: auto;
max-width: 90svw; max-width: 90svw;
max-height: 90svh; max-height: 90svh;
min-width: 100px; min-width: 100px;
min-height: 100px; min-height: 100px;
border-radius: 10px; border-radius: 10px;
border: 1px solid var(--white30a); border: 1px solid var(--white30a);
position: fixed; position: fixed;
padding: 10px; padding: 10px;
padding-top: 25px; padding-top: 25px;
display: none; display: none;
flex-direction: column; flex-direction: column;
box-shadow: 0 0 10px var(--black70a); box-shadow: 0 0 10px var(--black70a);
z-index: 3000; z-index: 3000;
left: 0; left: 0;
top: 0; top: 0;
margin: 0; margin: 0;
right: unset; right: unset;
width: calc(((100svw - var(--sheldWidth)) / 2) - 1px); width: calc(((100svw - var(--sheldWidth)) / 2) - 1px);
} }
.floating_prompt_radio_group { .floating_prompt_radio_group {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
#extension_floating_counter { #extension_floating_counter {
font-weight: 600; font-weight: 600;
color: orange; color: orange;
} }
.floating_prompt_settings textarea { .extension_token_counter {
font-size: calc(var(--mainFontSize) * 0.9); font-size: calc(var(--mainFontSize) * 0.9);
line-height: 1.2; width: 100%;
} text-align: right;
}
#ANClose {
height: 15px; .floating_prompt_settings textarea {
aspect-ratio: 1 / 1; font-size: calc(var(--mainFontSize) * 0.9);
font-size: 20px; line-height: 1.2;
opacity: 0.5; }
transition: all 250ms;
} #ANClose {
height: 15px;
#ANClose:hover { aspect-ratio: 1 / 1;
cursor: pointer; font-size: 20px;
opacity: 1; opacity: 0.5;
} transition: all 250ms;
}
.panelControlBar {
position: absolute; #ANClose:hover {
right: 5px; cursor: pointer;
top: 5px; opacity: 1;
margin-right: 5px; }
}
.panelControlBar {
#floatingPrompt .drag-grabber { position: absolute;
position: unset; right: 5px;
} top: 5px;
margin-right: 5px;
}
#floatingPrompt .drag-grabber {
position: unset;
}

View File

@ -547,7 +547,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
} }
// if not swipe - check if message generated already // if not swipe - check if message generated already
if (type !== "swipe" && !isMultigenEnabled() && chat.length == messagesBefore) { if (generateType === "group_chat" && !isMultigenEnabled() && chat.length == messagesBefore) {
await delay(100); await delay(100);
} }
// if swipe - see if message changed // if swipe - see if message changed
@ -1418,6 +1418,14 @@ function onGroupScenarioRemoveClick() {
$(this).closest('.group_scenario').find('.group_chat_scenario').val('').trigger('input'); $(this).closest('.group_scenario').find('.group_chat_scenario').val('').trigger('input');
} }
function onSendTextareaInput() {
if (is_group_automode_enabled) {
// Wait for current automode generation to finish
is_group_automode_enabled = false;
$("#rm_group_automode").prop("checked", false);
}
}
function stopAutoModeGeneration() { function stopAutoModeGeneration() {
if (groupAutoModeAbortController) { if (groupAutoModeAbortController) {
groupAutoModeAbortController.abort(); groupAutoModeAbortController.abort();
@ -1440,4 +1448,5 @@ jQuery(() => {
is_group_automode_enabled = value; is_group_automode_enabled = value;
eventSource.once(event_types.GENERATION_STOPPED, stopAutoModeGeneration); eventSource.once(event_types.GENERATION_STOPPED, stopAutoModeGeneration);
}); });
$("#send_textarea").on("keyup", onSendTextareaInput);
}); });

View File

@ -44,7 +44,7 @@ If you have any objections to these requirements, please mention them specifical
If you accept the requirements, please confirm this by replying with "${DEFAULT_JAILBREAK_RESPONSE}", and nothing more. Upon receiving your accurate confirmation message, I will specify the context of the scene and {{char}}'s characteristics, background, and personality in the next message.`; If you accept the requirements, please confirm this by replying with "${DEFAULT_JAILBREAK_RESPONSE}", and nothing more. Upon receiving your accurate confirmation message, I will specify the context of the scene and {{char}}'s characteristics, background, and personality in the next message.`;
const DEFAULT_CHARACTER_NUDGE_MESSAGE = "[Unless otherwise stated by {{user}}, your the next response shall only be written from the point of view of {{char}}. Do not seek approval of your writing style at the end of the response.]"; const DEFAULT_CHARACTER_NUDGE_MESSAGE = "[Unless otherwise stated by {{user}}, your the next response shall only be written from the point of view of {{char}}. Do not seek approval of your writing style at the end of the response. Don't reply with <ACK>.]";
const DEFAULT_IMPERSONATION_PROMPT = "[Write 1 reply only in internet RP style from the point of view of {{user}}, using the chat history so far as a guideline for the writing style of {{user}}. Don't write as {{char}} or system.]"; const DEFAULT_IMPERSONATION_PROMPT = "[Write 1 reply only in internet RP style from the point of view of {{user}}, using the chat history so far as a guideline for the writing style of {{user}}. Don't write as {{char}} or system.]";
const poe_settings = { const poe_settings = {
@ -265,7 +265,7 @@ async function generatePoe(type, finalPrompt, signal) {
const isQuiet = type === 'quiet'; const isQuiet = type === 'quiet';
let reply = ''; let reply = '';
if (max_context > POE_TOKEN_LENGTH) { if (max_context > POE_TOKEN_LENGTH && poe_settings.bot !== 'a2_100k') {
console.debug('Prompt is too long, sending in chunks'); console.debug('Prompt is too long, sending in chunks');
const result = await sendChunkedMessage(finalPrompt, !isQuiet, signal) const result = await sendChunkedMessage(finalPrompt, !isQuiet, signal)
reply = result.reply; reply = result.reply;

View File

@ -146,6 +146,7 @@ let power_user = {
}, },
personas: {}, personas: {},
default_persona: null,
}; };
let themes = []; let themes = [];

View File

@ -98,7 +98,7 @@ const getSlashCommandsHelp = parser.getHelpString.bind(parser);
parser.addCommand('help', helpCommandCallback, ['?'], ' displays this help message', true, true); parser.addCommand('help', helpCommandCallback, ['?'], ' displays this help message', true, true);
parser.addCommand('name', setNameCallback, ['persona'], '<span class="monospace">(name)</span> sets user name and persona avatar (if set)', true, true); parser.addCommand('name', setNameCallback, ['persona'], '<span class="monospace">(name)</span> sets user name and persona avatar (if set)', true, true);
parser.addCommand('sync', syncCallback, [], ' syncs user name in user-attributed messages in the current chat', true, true); parser.addCommand('sync', syncCallback, [], ' syncs user name in user-attributed messages in the current chat', true, true);
parser.addCommand('bind', bindCallback, [], ' binds/unbinds a persona (name and avatar) to the current chat', true, true); parser.addCommand('lock', bindCallback, ['bind'], ' locks/unlocks a persona (name and avatar) to the current chat', true, true);
parser.addCommand('bg', setBackgroundCallback, ['background'], '<span class="monospace">(filename)</span> sets a background according to filename, partial names allowed, will set the first one alphabetically if multiple files begin with the provided argument string', false, true); parser.addCommand('bg', setBackgroundCallback, ['background'], '<span class="monospace">(filename)</span> sets a background according to filename, partial names allowed, will set the first one alphabetically if multiple files begin with the provided argument string', false, true);
parser.addCommand('sendas', sendMessageAs, [], ` sends message as a specific character.<br>Example:<br><pre><code>/sendas Chloe\nHello, guys!</code></pre>will send "Hello, guys!" from "Chloe".<br>Uses character avatar if it exists in the characters list.`, true, true); parser.addCommand('sendas', sendMessageAs, [], ` sends message as a specific character.<br>Example:<br><pre><code>/sendas Chloe\nHello, guys!</code></pre>will send "Hello, guys!" from "Chloe".<br>Uses character avatar if it exists in the characters list.`, true, true);
parser.addCommand('sys', sendNarratorMessage, [], '<span class="monospace">(text)</span> sends message as a system narrator', false, true); parser.addCommand('sys', sendNarratorMessage, [], '<span class="monospace">(text)</span> sends message as a system narrator', false, true);
@ -262,6 +262,7 @@ function executeSlashCommands(text) {
continue; continue;
} }
console.debug('Slash command executing:', result);
result.command.callback(result.args, result.value); result.command.callback(result.args, result.value);
if (result.command.interruptsGeneration) { if (result.command.interruptsGeneration) {

View File

@ -34,6 +34,7 @@
--orangered: rgb(255, 90, 0); --orangered: rgb(255, 90, 0);
--greyCAIbg: rgb(36, 36, 37); --greyCAIbg: rgb(36, 36, 37);
--ivory: rgb(220, 220, 210); --ivory: rgb(220, 220, 210);
--golden: rgba(212, 175, 55, 1);
/*Default Theme, will be changed by ToolCool Color Picker*/ /*Default Theme, will be changed by ToolCool Color Picker*/
@ -296,6 +297,7 @@ hr {
background-image: linear-gradient(90deg, var(--transparent), var(--white30a), var(--transparent)); background-image: linear-gradient(90deg, var(--transparent), var(--white30a), var(--transparent));
margin: 5px 0; margin: 5px 0;
height: 1px; height: 1px;
min-height: 1px;
border: 0; border: 0;
} }
@ -895,6 +897,10 @@ select {
margin: 5px 0; margin: 5px 0;
} }
.margin5 {
margin: 5px;
}
#description_textarea, #description_textarea,
#firstmessage_textarea { #firstmessage_textarea {
height: -webkit-fill-available; height: -webkit-fill-available;
@ -993,10 +999,17 @@ input[type="file"] {
gap: 10px; gap: 10px;
} }
#right-nav-panel-tabs .right_menu_button { #right-nav-panel-tabs .right_menu_button,
#CharListButtonAndHotSwaps .right_menu_button {
padding-right: 0; padding-right: 0;
} }
#chartokenwarning.menu_button {
font-size: unset;
height: fit-content;
aspect-ratio: unset;
}
/* ##################################################################### */ /* ##################################################################### */
/* Right Panel's Upper Tabs */ /* Right Panel's Upper Tabs */
/* ##################################################################### */ /* ##################################################################### */
@ -1239,7 +1252,8 @@ select option:not(:checked) {
} }
#form_character_search_form .menu_button, #form_character_search_form .menu_button,
#GroupFavDelOkBack .menu_button { #GroupFavDelOkBack .menu_button,
.avatar-container .menu_button {
margin: 0; margin: 0;
height: fit-content; height: fit-content;
padding: 5px; padding: 5px;
@ -1326,6 +1340,10 @@ input[type=search]:focus::-webkit-search-cancel-button {
width: calc(100% - 70px); width: calc(100% - 70px);
} }
.wideMax100px {
max-width: 100px;
}
.widthUnset { .widthUnset {
width: unset; width: unset;
} }
@ -1432,7 +1450,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
width: 100%; width: 100%;
flex-wrap: wrap; flex-wrap: wrap;
margin-top: 0px; margin-top: 0px;
margin-bottom: 6px; /* margin-bottom: 6px; */
align-items: center; align-items: center;
} }
@ -1446,7 +1464,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
display: flex; display: flex;
flex: 0 0 100%; flex: 0 0 100%;
flex-wrap: wrap; flex-wrap: wrap;
margin-bottom: 4px; /* margin-bottom: 4px; */
} }
@ -1529,21 +1547,35 @@ input[type=search]:focus::-webkit-search-cancel-button {
pointer-events: all; pointer-events: all;
} }
.avatar-buttons-bottom {
bottom: 0;
left: 0;
}
.avatar-buttons-top {
top: 0;
left: 0;
}
/* Ross should be able to handle this later */
/*.big-avatars .avatar-buttons{
justify-content: center;
width: fit-content;
}*/
.avatar-buttons { .avatar-buttons {
pointer-events: none; pointer-events: none;
display: none; display: none;
position: absolute; position: absolute;
top: 0;
left: 0;
width: 100%; width: 100%;
justify-content: space-between; justify-content: space-between;
} }
.avatar_div .avatar { .avatar_div .avatar {
margin-left: 4px; /* margin-left: 4px;
margin-right: 10px; margin-right: 10px;
height: 70px; height: 70px;
width: 70px; width: 70px; */
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -1612,7 +1644,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
} }
#result_info { #result_info {
font-size: calc(var(--mainFontSize) - 0.2rem); font-size: calc(var(--mainFontSize) - 0.1rem);
font-weight: bold; font-weight: bold;
} }
@ -1885,27 +1917,6 @@ input[type=search]:focus::-webkit-search-cancel-button {
opacity: 0.8; opacity: 0.8;
} }
#world_popup_bottom_holder div:not(:first-of-type) {
margin-left: 1rem;
}
#world_info_buttons {
margin-left: 1rem;
}
.world_entry {
padding: 0 5px;
}
.world_entry:not(:last-child)::after {
margin-top: 1rem;
height: 1px;
display: block;
width: 100%;
content: '';
background-image: linear-gradient(270deg, rgba(0, 0, 0, 0), rgba(100, 100, 100, 0.75), rgba(0, 0, 0, 0));
}
.world_popup_logo_block { .world_popup_logo_block {
display: flex; display: flex;
align-items: center; align-items: center;
@ -1980,7 +1991,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
.world_entry_form_control { .world_entry_form_control {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin: 0 10px; /* margin: 0 10px; */
} }
.world_entry_thin_controls { .world_entry_thin_controls {
@ -1998,7 +2009,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
.world_entry_form_control label h4 { .world_entry_form_control label h4 {
margin-bottom: 0px; margin-bottom: 0px;
margin-top: 0.5rem; margin-top: 5px;
} }
.world_entry_form_control label h5 { .world_entry_form_control label h5 {
@ -2010,12 +2021,13 @@ input[type=search]:focus::-webkit-search-cancel-button {
height: auto; height: auto;
/* width: auto; */ /* width: auto; */
margin-top: 0; margin-top: 0;
margin-bottom: 0;
} }
.world_entry_form_control.world_entry_form_horizontal { .world_entry_form_control.world_entry_form_horizontal {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
margin-top: 5px; /* margin-top: 5px; */
flex-wrap: wrap; flex-wrap: wrap;
} }
@ -2077,6 +2089,11 @@ input[type=search]:focus::-webkit-search-cancel-button {
margin-right: 12px; margin-right: 12px;
} }
/* Override toastr default styles */
body #toast-container>div {
opacity: 0.95;
}
#dialogue_del_mes { #dialogue_del_mes {
display: none; display: none;
} }
@ -2152,6 +2169,15 @@ input[type='checkbox']:not(#nav-toggle):not(#rm_button_panel_pin):not(#lm_button
outline: 2px solid transparent; outline: 2px solid transparent;
} }
#user_avatar_block .default_persona .avatar {
border: 2px solid var(--golden);
box-sizing: content-box;
}
#user_avatar_block .default_persona .set_default_persona {
color: var(--golden);
}
#user_avatar_block .avatar img { #user_avatar_block .avatar img {
width: 64px; width: 64px;
height: 64px; height: 64px;
@ -2253,8 +2279,8 @@ input[type="range"]::-webkit-slider-thumb {
/*Notes '?' links*/ /*Notes '?' links*/
.note-link-span { .note-link-span {
color: var(--sienna); color: var(--SmartThemeQuoteColor);
border: 1px solid var(--sienna); border: 1px solid var(--SmartThemeQuoteColor);
border-radius: 10px; border-radius: 10px;
line-height: var(--mainFontSize); line-height: var(--mainFontSize);
font-size: var(--mainFontSize); font-size: var(--mainFontSize);
@ -3852,6 +3878,10 @@ toolcool-color-picker {
margin: 0; margin: 0;
} }
.margin0auto {
margin: 0 auto;
}
.margin-r5 { .margin-r5 {
margin-right: 5px; margin-right: 5px;
} }
@ -4321,7 +4351,7 @@ body.waifuMode #avatar_zoom_popup {
} }
.world_entry_form_control.world_entry_form_horizontal { .world_entry_form_control.world_entry_form_horizontal {
flex-direction: column; /* flex-direction: column; */
align-items: flex-start; align-items: flex-start;
row-gap: 0.5rem; row-gap: 0.5rem;
} }
@ -4462,9 +4492,9 @@ body.waifuMode #avatar_zoom_popup {
font-size: calc(var(--mainFontSize) - .1rem); font-size: calc(var(--mainFontSize) - .1rem);
} }
.avatar_div { /* .avatar_div {
margin-top: 5px; margin-top: 5px;
} } */
#character_popup { #character_popup {
width: 100%; width: 100%;
@ -4482,7 +4512,7 @@ body.waifuMode #avatar_zoom_popup {
} }
.drawer25pWidth { .drawer25pWidth {
flex-basis: max(calc(100% / 4 - 10px), 200px); flex-basis: max(calc(100% / 4 - 10px), 190px);
} }
.expression-holder { .expression-holder {
@ -4550,7 +4580,7 @@ body.waifuMode #avatar_zoom_popup {
@media screen and (max-width: 450px) { @media screen and (max-width: 450px) {
.drawer25pWidth { .drawer25pWidth {
flex-basis: max(calc(100% / 2 - 10px), 200px); flex-basis: max(calc(100% / 2 - 10px), 180px);
} }
} }

View File

@ -385,9 +385,8 @@ app.post("/generate", jsonParser, async function (request, response_generate = r
signal: controller.signal, signal: controller.signal,
}; };
const MAX_RETRIES = 10; const MAX_RETRIES = 50;
const delayAmount = 3000; const delayAmount = 2500;
let fetch, url, response; let fetch, url, response;
for (let i = 0; i < MAX_RETRIES; i++) { for (let i = 0; i < MAX_RETRIES; i++) {
try { try {
@ -420,15 +419,23 @@ app.post("/generate", jsonParser, async function (request, response_generate = r
} }
} catch (error) { } catch (error) {
// response // response
switch (error.statusCode) { switch (error?.status) {
case 403:
case 503: // retry in case of temporary service issue, possibly caused by a queue failure? case 503: // retry in case of temporary service issue, possibly caused by a queue failure?
console.debug(`KoboldAI is busy. Retry attempt ${i+1} of ${MAX_RETRIES}...`);
await delay(delayAmount); await delay(delayAmount);
break; break;
default: default:
if ('status' in error) {
console.log('Status Code from Kobold:', error.status);
}
return response_generate.send({ error: true }); return response_generate.send({ error: true });
} }
} }
} }
console.log('Max retries exceeded. Giving up.');
return response_generate.send({ error: true });
}); });
//************** Text generation web UI //************** Text generation web UI
@ -685,11 +692,11 @@ function getVersion() {
pkgVersion = pkgJson.version; pkgVersion = pkgJson.version;
if (!process.pkg && commandExistsSync('git')) { if (!process.pkg && commandExistsSync('git')) {
gitRevision = require('child_process') gitRevision = require('child_process')
.execSync('git rev-parse --short HEAD', { cwd: process.cwd() }) .execSync('git rev-parse --short HEAD', { cwd: process.cwd(), stdio: ['ignore', 'pipe', 'ignore'] })
.toString().trim(); .toString().trim();
gitBranch = require('child_process') gitBranch = require('child_process')
.execSync('git rev-parse --abbrev-ref HEAD', { cwd: process.cwd() }) .execSync('git rev-parse --abbrev-ref HEAD', { cwd: process.cwd(), stdio: ['ignore', 'pipe', 'ignore'] })
.toString().trim(); .toString().trim();
} }
} }
@ -2421,7 +2428,7 @@ app.post('/generate_poe', jsonParser, async (request, response) => {
if (streaming) { if (streaming) {
try { try {
let reply = ''; let reply = '';
for await (const mes of client.send_message(bot, prompt, false, 30, abortController.signal)) { for await (const mes of client.send_message(bot, prompt, false, 60, abortController.signal)) {
if (response.headersSent === false) { if (response.headersSent === false) {
response.writeHead(200, { response.writeHead(200, {
'Content-Type': 'text/plain;charset=utf-8', 'Content-Type': 'text/plain;charset=utf-8',
@ -2454,7 +2461,7 @@ app.post('/generate_poe', jsonParser, async (request, response) => {
try { try {
let reply; let reply;
let messageId; let messageId;
for await (const mes of client.send_message(bot, prompt, false, 30, abortController.signal)) { for await (const mes of client.send_message(bot, prompt, false, 60, abortController.signal)) {
reply = mes.text; reply = mes.text;
messageId = mes.messageId; messageId = mes.messageId;
} }
@ -3151,7 +3158,7 @@ async function postAsync(url, args) {
return data; return data;
} }
throw new Error(response); throw response;
} }
function getAsync(url, args) { function getAsync(url, args) {
@ -3179,6 +3186,10 @@ const autorunUrl = new URL(
); );
const setupTasks = async function () { const setupTasks = async function () {
const version = getVersion();
console.log(`SillyTavern ${version.pkgVersion}` + (version.gitBranch ? ` '${version.gitBranch}' (${version.gitRevision})` : ''));
migrateSecrets(); migrateSecrets();
ensurePublicDirectoriesExist(); ensurePublicDirectoriesExist();
await ensureThumbnailCache(); await ensureThumbnailCache();
@ -3196,6 +3207,10 @@ const setupTasks = async function () {
if (autorun) open(autorunUrl.toString()); if (autorun) open(autorunUrl.toString());
console.log('SillyTavern is listening on: ' + tavernUrl); console.log('SillyTavern is listening on: ' + tavernUrl);
if (listen) {
console.log('\n0.0.0.0 means SillyTavern is listening on all network interfaces (Wi-Fi, LAN, localhost). If you want to limit it only to internal localhost (127.0.0.1), change the setting in config.conf to “listen=false”\n');
}
} }
if (listen && !config.whitelistMode && !config.basicAuthMode) { if (listen && !config.whitelistMode && !config.basicAuthMode) {

View File

@ -608,7 +608,7 @@ class Client {
} }
} }
async *send_message(chatbot, message, with_chat_break = false, timeout = 30, signal = null) { async *send_message(chatbot, message, with_chat_break = false, timeout = 60, signal = null) {
await this.ws_ping(); await this.ws_ping();
if (this.auto_reconnect) { if (this.auto_reconnect) {