mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-10 00:50:11 +01:00
merge
This commit is contained in:
commit
3df439a224
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@ public/css/bg_load.css
|
||||
public/themes/
|
||||
public/OpenAI Settings/
|
||||
public/KoboldAI Settings/
|
||||
public/NovelAI Settings/
|
||||
public/TextGen Settings/
|
||||
public/scripts/extensions/third-party/
|
||||
public/stats.json
|
||||
|
@ -64,11 +64,6 @@
|
||||
"collapse_newlines": false,
|
||||
"pygmalion_formatting": 0,
|
||||
"pin_examples": false,
|
||||
"disable_description_formatting": false,
|
||||
"disable_scenario_formatting": false,
|
||||
"disable_personality_formatting": false,
|
||||
"disable_examples_formatting": false,
|
||||
"disable_start_formatting": false,
|
||||
"trim_sentences": false,
|
||||
"include_newline": false,
|
||||
"always_force_name2": true,
|
||||
@ -77,7 +72,6 @@
|
||||
"multigen": false,
|
||||
"multigen_first_chunk": 50,
|
||||
"multigen_next_chunks": 30,
|
||||
"custom_chat_separator": "",
|
||||
"markdown_escape_strings": "",
|
||||
"fast_ui_mode": false,
|
||||
"avatar_style": 0,
|
||||
@ -312,9 +306,6 @@
|
||||
"None": {}
|
||||
}
|
||||
},
|
||||
"context_settings": {
|
||||
"selected_template": ""
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"id": "1345561466591",
|
||||
@ -334,21 +325,22 @@
|
||||
]
|
||||
},
|
||||
"nai_settings": {
|
||||
"temperature": 0.63,
|
||||
"repetition_penalty": 1.148125,
|
||||
"temperature": 1.5,
|
||||
"repetition_penalty": 2.25,
|
||||
"repetition_penalty_range": 2048,
|
||||
"repetition_penalty_slope": 0.09,
|
||||
"repetition_penalty_frequency": 0,
|
||||
"repetition_penalty_presence": 0,
|
||||
"repetition_penalty_presence": 0.005,
|
||||
"tail_free_sampling": 0.975,
|
||||
"top_k": 0,
|
||||
"top_p": 0.975,
|
||||
"top_a": 1,
|
||||
"typical_p": 1,
|
||||
"top_k": 10,
|
||||
"top_p": 0.75,
|
||||
"top_a": 0.08,
|
||||
"typical_p": 0.975,
|
||||
"min_length": 1,
|
||||
"model_novel": "euterpe-v2",
|
||||
"preset_settings_novel": "Classic-Euterpe",
|
||||
"streaming_novel": false
|
||||
"model_novel": "clio-v1",
|
||||
"preset_settings_novel": "Talker-Chat-Clio",
|
||||
"streaming_novel": true,
|
||||
"order": [1, 5, 0, 2, 3, 4]
|
||||
},
|
||||
"kai_settings": {
|
||||
"temp": 1,
|
||||
|
32
package-lock.json
generated
32
package-lock.json
generated
@ -43,6 +43,7 @@
|
||||
"simple-git": "^3.19.1",
|
||||
"uniqolor": "^1.1.0",
|
||||
"webp-converter": "2.3.2",
|
||||
"write-file-atomic": "^5.0.1",
|
||||
"ws": "^8.13.0",
|
||||
"yargs": "^17.7.1",
|
||||
"yauzl": "^2.10.0"
|
||||
@ -1805,6 +1806,14 @@
|
||||
"@types/node": "16.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
|
||||
"engines": {
|
||||
"node": ">=0.8.19"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
@ -3073,6 +3082,17 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
@ -3523,6 +3543,18 @@
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/write-file-atomic": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
|
||||
"integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
|
||||
"dependencies": {
|
||||
"imurmurhash": "^0.1.4",
|
||||
"signal-exit": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.13.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@dqbd/tiktoken": "^1.0.2",
|
||||
"@agnai/sentencepiece-js": "^1.1.1",
|
||||
"@agnai/web-tokenizers": "^0.1.3",
|
||||
"@dqbd/tiktoken": "^1.0.2",
|
||||
"axios": "^1.4.0",
|
||||
"command-exists": "^1.2.9",
|
||||
"compression": "^1",
|
||||
@ -30,10 +31,10 @@
|
||||
"png-chunks-extract": "^1.0.0",
|
||||
"response-time": "^2.3.2",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"@agnai/sentencepiece-js": "^1.1.1",
|
||||
"simple-git": "^3.19.1",
|
||||
"uniqolor": "^1.1.0",
|
||||
"webp-converter": "2.3.2",
|
||||
"write-file-atomic": "^5.0.1",
|
||||
"ws": "^8.13.0",
|
||||
"yargs": "^17.7.1",
|
||||
"yauzl": "^2.10.0"
|
||||
|
@ -1,16 +1,16 @@
|
||||
{
|
||||
"order": [5, 0, 1, 3, 7],
|
||||
"temperature": 1.35,
|
||||
"max_length": 300,
|
||||
"order": [5, 0, 1, 3],
|
||||
"temperature": 1.16,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_k": 225,
|
||||
"top_g": 8,
|
||||
"typical_p": 0.975,
|
||||
"tail_free_sampling": 0.984,
|
||||
"repetition_penalty": 1.7,
|
||||
"repetition_penalty_range": 3200,
|
||||
"top_k": 175,
|
||||
"typical_p": 0.96,
|
||||
"tail_free_sampling": 0.994,
|
||||
"repetition_penalty": 1.68,
|
||||
"repetition_penalty_range": 2240,
|
||||
"repetition_penalty_slope": 1.5,
|
||||
"repetition_penalty_frequency": 0,
|
||||
"repetition_penalty_presence": 0.02,
|
||||
"repetition_penalty_presence": 0.005,
|
||||
"use_cache": false,
|
||||
"return_full_text": false,
|
||||
"prefix": "vanilla",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [6, 0, 1, 2, 3],
|
||||
"temperature": 1,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_k": 25,
|
||||
"top_p": 1,
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [6, 2, 3, 1, 0],
|
||||
"temperature": 1,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_k": 0,
|
||||
"top_p": 0.96,
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [2, 3, 0, 4, 1],
|
||||
"temperature": 1.35,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_k": 15,
|
||||
"top_p": 0.85,
|
||||
|
20
public/NovelAI Settings/CosmicCube-Kayra.settings
Normal file
20
public/NovelAI Settings/CosmicCube-Kayra.settings
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"order": [8, 6, 5, 0, 3],
|
||||
"temperature": 0.9,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"typical_p": 0.95,
|
||||
"tail_free_sampling": 0.92,
|
||||
"mirostat_lr": 0.22,
|
||||
"mirostat_tau": 4.95,
|
||||
"repetition_penalty": 3,
|
||||
"repetition_penalty_range": 4000,
|
||||
"repetition_penalty_frequency": 0,
|
||||
"repetition_penalty_presence": 0,
|
||||
"use_cache": false,
|
||||
"return_full_text": false,
|
||||
"prefix": "vanilla",
|
||||
"phrase_rep_pen": "off",
|
||||
"cfg_scale": 1.48,
|
||||
"max_context": 7800
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [4, 0, 5, 3, 2],
|
||||
"temperature": 1.09,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_p": 0.969,
|
||||
"top_a": 0.09,
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [0, 1, 2, 3],
|
||||
"temperature": 1,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_k": 25,
|
||||
"top_p": 1,
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [6, 0, 8, 5, 3],
|
||||
"temperature": 1.5,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"typical_p": 0.95,
|
||||
"tail_free_sampling": 0.95,
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [6, 0, 4, 1, 2, 5, 3],
|
||||
"temperature": 1.31,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_k": 25,
|
||||
"top_p": 0.97,
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [3, 4, 5, 0],
|
||||
"temperature": 1.06,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_a": 0.146,
|
||||
"typical_p": 0.976,
|
||||
|
@ -1,17 +1,17 @@
|
||||
{
|
||||
"order": [3, 0, 5],
|
||||
"temperature": 2.5,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"typical_p": 0.966,
|
||||
"tail_free_sampling": 0.933,
|
||||
"typical_p": 0.969,
|
||||
"tail_free_sampling": 0.941,
|
||||
"repetition_penalty": 1,
|
||||
"repetition_penalty_range": 2048,
|
||||
"repetition_penalty_range": 1024,
|
||||
"repetition_penalty_frequency": 0,
|
||||
"repetition_penalty_presence": 0,
|
||||
"use_cache": false,
|
||||
"return_full_text": false,
|
||||
"prefix": "vanilla",
|
||||
"phrase_rep_pen": "aggressive",
|
||||
"phrase_rep_pen": "medium",
|
||||
"max_context": 7800
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [1, 5, 0, 2, 3, 4],
|
||||
"temperature": 1.5,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_k": 10,
|
||||
"top_p": 0.75,
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [5, 0, 4],
|
||||
"temperature": 1,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_a": 0.017,
|
||||
"typical_p": 0.975,
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"order": [6, 0, 5],
|
||||
"temperature": 0.895,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"typical_p": 0.9,
|
||||
"repetition_penalty": 2,
|
||||
|
@ -1,15 +1,15 @@
|
||||
{
|
||||
"order": [8, 0, 5, 3, 2, 4],
|
||||
"temperature": 1.5,
|
||||
"max_length": 300,
|
||||
"max_length": 150,
|
||||
"min_length": 1,
|
||||
"top_a": 0.02,
|
||||
"top_p": 0.95,
|
||||
"typical_p": 0.95,
|
||||
"tail_free_sampling": 0.95,
|
||||
"mirostat_lr": 0.2,
|
||||
"mirostat_lr": 0.25,
|
||||
"mirostat_tau": 5,
|
||||
"repetition_penalty": 1.6,
|
||||
"repetition_penalty": 1.625,
|
||||
"repetition_penalty_range": 2016,
|
||||
"repetition_penalty_frequency": 0,
|
||||
"repetition_penalty_presence": 0,
|
||||
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "Classic",
|
||||
"storyString": "{{instructSystemPrompt}}\n{{wiBeforeCharacter}}\n{{description}}\n{{char}}'s personality: {{personality}}\nCircumstances and context of the dialogue: {{scenario}}\n{{wiAfterCharacter}}\nThis is how {{char}} should talk\n{{mesExamples}}\nThen the roleplay chat between {{user}} and {{char}} begins\n",
|
||||
"injections": []
|
||||
}
|
6
public/context/Default.json
Normal file
6
public/context/Default.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "Default",
|
||||
"story_string": "{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}{{/if}}",
|
||||
"chat_start": "***",
|
||||
"example_separator": "***"
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "Pygmalion",
|
||||
"storyString": "{{instructSystemPrompt}}\n{{wiBeforeCharacter}}\n{{char}}'s Persona: {{description}}\nPersonality: {{personality}}\nScenario: {{scenario}}\n{{wiAfterCharacter}}\n<START>\n{{mesExamples}}\n<START>\n",
|
||||
"injections": []
|
||||
"story_string": "{{#if description}}{{{char}}}'s Persona: {{description}}{{/if}}\n{{#if personality}}Personality: {{personality}}{{/if}}\n{{#if scenario}}Scenario: {{scenario}}{{/if}}",
|
||||
"chat_start": "<START>",
|
||||
"example_separator": "<START>"
|
||||
}
|
||||
|
6
public/context/Roleplay.json
Normal file
6
public/context/Roleplay.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "Roleplay",
|
||||
"story_string": "### Input:\n{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}{{/if}}",
|
||||
"chat_start": "### New Roleplay:",
|
||||
"example_separator": "### New Roleplay:"
|
||||
}
|
6
public/context/simple-proxy-for-tavern.json
Normal file
6
public/context/simple-proxy-for-tavern.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "simple-proxy-for-tavern",
|
||||
"story_string": "### Input:\n{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}### Response:\n(OOC) Understood. I will take this info into account for the roleplay. (end OOC)",
|
||||
"chat_start": "### New Roleplay:",
|
||||
"example_separator": "### New Roleplay:"
|
||||
}
|
14
public/img/openrouter.svg
Normal file
14
public/img/openrouter.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<svg width="100%" height="100%" viewBox="0 0 512 512"
|
||||
xmlns="http://www.w3.org/2000/svg" class="Navbar_logo__INhgK" aria-label="Logo">
|
||||
<g clip-path="url(#clip0_205_3)">
|
||||
<path d="M3 248.945C18 248.945 76 236 106 219C136 202 136 202 198 158C276.497 102.293 332 120.945 423 120.945" stroke-width="90"></path>
|
||||
<path d="M511 121.5L357.25 210.268L357.25 32.7324L511 121.5Z"></path>
|
||||
<path d="M0 249C15 249 73 261.945 103 278.945C133 295.945 133 295.945 195 339.945C273.497 395.652 329 377 420 377" stroke-width="90"></path>
|
||||
<path d="M508 376.445L354.25 287.678L354.25 465.213L508 376.445Z"></path>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_205_3">
|
||||
<rect width="512" height="512"></rect>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 777 B |
@ -41,6 +41,8 @@
|
||||
<script src="scripts/seedrandom.min.js"></script>
|
||||
<script src="scripts/droll.js"></script>
|
||||
<script src="scripts/localforage.min.js"></script>
|
||||
<script src="scripts/handlebars.js"></script>
|
||||
<script src="scripts/pagination.js"></script>
|
||||
<script type="module" src="scripts/eventemitter.js"></script>
|
||||
<script type="module" src="scripts/power-user.js"></script>
|
||||
<script type="module" src="scripts/swiped-events.js"></script>
|
||||
@ -49,7 +51,8 @@
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<script>
|
||||
function applyLocale() {
|
||||
var language = navigator.language || navigator.userLanguage;
|
||||
const overrideLanguage = localStorage.getItem("language");
|
||||
var language = overrideLanguage || navigator.language || navigator.userLanguage;
|
||||
language = language.toLowerCase();
|
||||
console.log(language)
|
||||
//load the appropriate language file
|
||||
@ -93,10 +96,10 @@
|
||||
<script type="module" src="scripts/slash-commands.js"></script>
|
||||
<script type="module" src="scripts/tags.js"></script>
|
||||
<script type="module" src="scripts/secrets.js"></script>
|
||||
<script type="module" src="scripts/context-template.js"></script>
|
||||
<script type="module" src="scripts/extensions.js"></script>
|
||||
<script type="module" src="scripts/authors-note.js"></script>
|
||||
<script type="module" src="scripts/preset-manager.js"></script>
|
||||
<script type="module" src="scripts/filters.js"></script>
|
||||
<script type="text/javascript" src="scripts/toolcool-color-picker.js"></script>
|
||||
|
||||
<title>SillyTavern</title>
|
||||
@ -159,9 +162,16 @@
|
||||
<span class="note-link-span">?</span>
|
||||
</a>
|
||||
</h3>
|
||||
<select id="settings_perset_novel" data-preset-manager-for="novel">
|
||||
<option value="gui" data-i18n="default">Default</option>
|
||||
</select>
|
||||
<div class="preset_buttons">
|
||||
<select id="settings_perset_novel" data-preset-manager-for="novel">
|
||||
<option value="gui" data-i18n="default">Default</option>
|
||||
</select>
|
||||
<i data-preset-manager-update="novel" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i>
|
||||
<i data-preset-manager-new="novel" class="menu_button fa-solid fa-plus" title="Create new preset" data-i18n="[title]Create new preset"></i>
|
||||
<i data-preset-manager-import="novel" class="menu_button fa-solid fa-upload" title="Import preset" data-i18n="[title]Import preset"></i>
|
||||
<i data-preset-manager-export="novel" class="menu_button fa-solid fa-download" title="Export preset" data-i18n="[title]Export preset"></i>
|
||||
<i data-preset-manager-delete="novel" class="menu_button fa-solid fa-trash-can" title="Delete the preset" data-i18n="[title]Delete the preset"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="openai_api-presets">
|
||||
<div>
|
||||
@ -200,8 +210,7 @@
|
||||
<div class="range-block-title justifyLeft">
|
||||
AI Module
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft"
|
||||
data-i18n="Changes the style of the generated text.">
|
||||
<div class="toggle-description justifyLeft" data-i18n="Changes the style of the generated text.">
|
||||
Changes the style of the generated text.
|
||||
</div>
|
||||
<select id="nai_prefix">
|
||||
@ -831,7 +840,7 @@
|
||||
Samplers will be applied in a top-down order.
|
||||
Use with caution.
|
||||
</div>
|
||||
<div id="kobold_order">
|
||||
<div id="kobold_order" class="prompt_order">
|
||||
<div data-id="0">
|
||||
<span data-i18n="Top K">Top K</span>
|
||||
<small>0</small>
|
||||
@ -849,7 +858,7 @@
|
||||
<small>3</small>
|
||||
</div>
|
||||
<div data-id="4">
|
||||
<span data-i18n="Typical Sampling">Typical Sampling</span>
|
||||
<span data-i18n="Typical Sampling">Typical P Sampling</span>
|
||||
<small>4</small>
|
||||
</div>
|
||||
<div data-id="5">
|
||||
@ -876,7 +885,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft" data-i18n="Use style tags to modify the writing style of the output">
|
||||
Use style tags to modify the writing style of the output
|
||||
Use style tags to modify the writing style of the output.
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="nai_preamble_textarea" class="text_pole textarea_compact" name="nai_preamble" rows="2" placeholder=""></textarea>
|
||||
@ -893,6 +902,21 @@
|
||||
<textarea id="nai_banned_tokens" class="text_pole textarea_compact" name="nai_banned_tokens" rows="2" placeholder=""></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block">
|
||||
<div class="range-block-title title_restorable">
|
||||
<span data-i18n="Logit Bias">Logit Bias</span>
|
||||
<div id="novelai_logit_bias_new_entry" class="menu_button menu_button_icon">
|
||||
<i class="fa-xs fa-solid fa-plus"></i>
|
||||
<small data-i18n="Add">Add</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft" data-i18n="Helps to ban or reenforce the usage of certain words">
|
||||
Helps to ban or reinforce the usage of certain tokens.
|
||||
</div>
|
||||
<div class="flex-container flexFlowColumn wide100p">
|
||||
<div class="novelai_logit_bias_list"></div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="range-block">
|
||||
<div class="range-block-title justifyLeft" data-i18n="CFG Scale">
|
||||
@ -914,7 +938,7 @@
|
||||
<span data-i18n="Negative Prompt">Negative Prompt</span>
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="nai_cfg_uc" class="text_pole textarea_compact" name="cfg_uc" rows="2" data-i18n="[placeholder]Add text here that would make the AI generate things you don't want in your outputs." placeholder="Add text here that would make the AI generate things you don't want in your outputs."></textarea>
|
||||
<textarea id="nai_cfg_uc" class="text_pole textarea_compact" name="cfg_uc" rows="2" data-i18n="[placeholder]Add text here that would make the AI generate things you don't want in your outputs." placeholder="Add text here that would make the AI generate things you don't want in your outputs."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<small class="margin-bot-10px" data-i18n="Used if CFG Scale is unset globally, per chat or character">
|
||||
@ -966,21 +990,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block">
|
||||
<div class="range-block-title" data-i18n="Top G">
|
||||
Top G
|
||||
</div>
|
||||
<div class="range-block-range-and-counter">
|
||||
<div class="range-block-range">
|
||||
<input type="range" id="top_g_novel" name="volume" min="0" max="20" step="1">
|
||||
</div>
|
||||
<div class="range-block-counter">
|
||||
<div contenteditable="true" data-for="top_g_novel" id="top_g_counter_novel">
|
||||
select
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block">
|
||||
<div class="range-block-title" data-i18n="Mirostat Tau">
|
||||
Mirostat Tau
|
||||
@ -1041,6 +1050,57 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block flexFlowColumn">
|
||||
<div class="range-block-title">
|
||||
<span data-i18n="Samplers Order">Samplers Order</span>
|
||||
</div>
|
||||
<div class="toggle-description" data-i18n="Samplers will be applied in a top-down order. Use with caution.">
|
||||
Samplers will be applied in a top-down order. Use with caution.
|
||||
</div>
|
||||
<div id="novel_order" class="prompt_order">
|
||||
<div data-id="0">
|
||||
<span data-i18n="Temperature">Temperature</span>
|
||||
<small>0</small>
|
||||
<div class="toggle_button right_menu_button"></div>
|
||||
</div>
|
||||
<div data-id="1">
|
||||
<span data-i18n="Top K Sampling">Top K Sampling</span>
|
||||
<small>1</small>
|
||||
<div class="toggle_button right_menu_button"></div>
|
||||
</div>
|
||||
<div data-id="2">
|
||||
<span data-i18n="Nucleus Sampling">Nucleus Sampling</span>
|
||||
<small>2</small>
|
||||
<div class="toggle_button right_menu_button"></div>
|
||||
</div>
|
||||
<div data-id="3">
|
||||
<span data-i18n="Tail Free Sampling">Tail Free Sampling</span>
|
||||
<small>3</small>
|
||||
<div class="toggle_button right_menu_button"></div>
|
||||
</div>
|
||||
<div data-id="4">
|
||||
<span data-i18n="Top A Sampling">Top A Sampling</span>
|
||||
<small>4</small>
|
||||
<div class="toggle_button right_menu_button"></div>
|
||||
</div>
|
||||
<div data-id="5">
|
||||
<span data-i18n="Typical Sampling">Typical Sampling</span>
|
||||
<small>5</small>
|
||||
<div class="toggle_button right_menu_button"></div>
|
||||
</div>
|
||||
<div data-id="6">
|
||||
<span data-i18n="CFG">CFG</span>
|
||||
<small>6</small>
|
||||
<div class="toggle_button right_menu_button"></div>
|
||||
</div>
|
||||
<!-- Yes, there is no 7. It was a removed Top G sampling. RIP. -->
|
||||
<div data-id="8">
|
||||
<span data-i18n="Mirostat">Mirostat</span>
|
||||
<small>8</small>
|
||||
<div class="toggle_button right_menu_button"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="textgenerationwebui_api-settings">
|
||||
<div class="range-block">
|
||||
@ -1207,7 +1267,7 @@
|
||||
<span data-i18n="Negative Prompt">Negative Prompt</span>
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="negative_prompt_textgenerationwebui" class="text_pole textarea_compact" name="negative_prompt" rows="2" data-i18n="[placeholder]Add text here that would make the AI generate things you don't want in your outputs." placeholder="Add text here that would make the AI generate things you don't want in your outputs."></textarea>
|
||||
<textarea id="negative_prompt_textgenerationwebui" class="text_pole textarea_compact" name="negative_prompt" rows="2" data-i18n="[placeholder]Add text here that would make the AI generate things you don't want in your outputs." placeholder="Add text here that would make the AI generate things you don't want in your outputs."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<small class="margin-bot-10px" data-i18n="Used if CFG Scale is unset globally, per chat or character">
|
||||
@ -1418,8 +1478,7 @@
|
||||
<div class="fa-solid fa-clock-rotate-left"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft"
|
||||
data-i18n="Prompt that is used when the NSFW toggle is O">
|
||||
<div class="toggle-description justifyLeft" data-i18n="Prompt that is used when the NSFW toggle is O">
|
||||
Prompt that is used when the NSFW toggle is OFF
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
@ -1435,9 +1494,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="Set at the beginning of the chat history to indicate that a new chat is about to start.">
|
||||
Set at the beginning of the chat history to indicate that a new chat is about to start.
|
||||
</span>
|
||||
<span data-i18n="Set at the beginning of the chat history to indicate that a new chat is about to start.">
|
||||
Set at the beginning of the chat history to indicate that a new chat is about to start.
|
||||
</span>
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="newchat_prompt_textarea" class="text_pole textarea_compact" name="new_chat" rows="3" placeholder=""></textarea>
|
||||
@ -1451,9 +1510,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="Set at the beginning of the chat history to indicate that a new group chat is about to start.">
|
||||
Set at the beginning of the chat history to indicate that a new group chat is about to start.
|
||||
</span>
|
||||
<span data-i18n="Set at the beginning of the chat history to indicate that a new group chat is about to start.">
|
||||
Set at the beginning of the chat history to indicate that a new group chat is about to start.
|
||||
</span>
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="newgroupchat_prompt_textarea" class="text_pole textarea_compact" name="new_group_chat" rows="3" placeholder=""></textarea>
|
||||
@ -1467,9 +1526,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.">
|
||||
Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.
|
||||
</span>
|
||||
<span data-i18n="Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.">
|
||||
Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.
|
||||
</span>
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="newexamplechat_prompt_textarea" class="text_pole textarea_compact" name="new_example_chat" rows="3" placeholder=""></textarea>
|
||||
@ -1483,9 +1542,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="Set at the beginning of the chat history to indicate that a new chat is about to start.">
|
||||
Set at the end of the chat history when the continue button is pressed.
|
||||
</span>
|
||||
<span data-i18n="Set at the beginning of the chat history to indicate that a new chat is about to start.">
|
||||
Set at the end of the chat history when the continue button is pressed.
|
||||
</span>
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="continue_nudge_prompt_textarea" class="text_pole textarea_compact" name="continue_nudge" rows="3" placeholder=""></textarea>
|
||||
@ -1496,9 +1555,9 @@
|
||||
Replace empty message
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="Send this text instead of nothing when the text box is empty.">
|
||||
Send this text instead of nothing when the text box is empty.
|
||||
</span>
|
||||
<span data-i18n="Send this text instead of nothing when the text box is empty.">
|
||||
Send this text instead of nothing when the text box is empty.
|
||||
</span>
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="send_if_empty_textarea" class="text_pole textarea_compact" name="send_if_empty" rows="3" placeholder=""></textarea>
|
||||
@ -1947,58 +2006,40 @@
|
||||
</h3>
|
||||
<div class="flex-container">
|
||||
<div name="PygOverrides" class="flex1">
|
||||
<h4><span data-i18n="AutoFormat Overrides">AutoFormat Overrides</span></h4>
|
||||
<label class="checkbox_label" for="disable-description-formatting-checkbox">
|
||||
<input id="disable-description-formatting-checkbox" type="checkbox" />
|
||||
<span data-i18n="Disable description formatting">Disable description formatting</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="disable-scenario-formatting-checkbox">
|
||||
<input id="disable-scenario-formatting-checkbox" type="checkbox" />
|
||||
<span data-i18n="Disable scenario formatting"> Disable scenario formatting</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="disable-personality-formatting-checkbox">
|
||||
<input id="disable-personality-formatting-checkbox" type="checkbox" />
|
||||
<span data-i18n="Disable personality formatting"> Disable personality formatting</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="disable-examples-formatting-checkbox">
|
||||
<input id="disable-examples-formatting-checkbox" type="checkbox" />
|
||||
<span data-i18n="Disable example chats formatting">Disable example chats formatting</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="disable-start-formatting-checkbox">
|
||||
<input id="disable-start-formatting-checkbox" type="checkbox" />
|
||||
<span data-i18n="Disable chat start formatting">Disable chat start formatting</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="trim_spaces">
|
||||
<input id="trim_spaces" type="checkbox" />
|
||||
<span data-i18n="Trim spaces">Trim spaces</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="trim_sentences_checkbox">
|
||||
<input id="trim_sentences_checkbox" type="checkbox" />
|
||||
<span data-i18n="Trim Incomplete Sentences">Trim Incomplete Sentences</span>
|
||||
</label>
|
||||
<!-- Add margin since this is a child of above -->
|
||||
<label class="checkbox_label indent20p" for="include_newline_checkbox">
|
||||
<input id="include_newline_checkbox" type="checkbox" />
|
||||
<span data-i18n="Include Newline">Include Newline</span>
|
||||
</label>
|
||||
<div>
|
||||
<h4 data-i18n="Custom Chat Separator">
|
||||
Custom Chat Separator
|
||||
<h4 data-i18n="Context Template">
|
||||
Context Template
|
||||
</h4>
|
||||
<div class="flex-container flexGap5">
|
||||
<select id="context_presets" class="flex1 margin0">
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<textarea id="custom_chat_separator" class="text_pole textarea_compact" type="text" placeholder="<START>" maxlength="500" rows="1"></textarea>
|
||||
<label for="context_story_string" data-i18n="Story String">
|
||||
Story String
|
||||
</label>
|
||||
<textarea id="context_story_string" class="text_pole textarea_compact" rows="3"></textarea>
|
||||
<div class="flex-container">
|
||||
<div class="flex1">
|
||||
<label for="context_example_separator">
|
||||
<span data-i18n="Example Separator">Example Separator</span>
|
||||
</label>
|
||||
<div>
|
||||
<textarea id="context_example_separator" class="text_pole textarea_compact" maxlength="500" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
<label for="context_chat_start">
|
||||
<span data-i18n="Chat Start">Chat Start</span>
|
||||
</label>
|
||||
<div>
|
||||
<textarea id="context_chat_start" class="text_pole textarea_compact" maxlength="500" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 data-i18n="Non-markdown strings">
|
||||
Non-markdown strings
|
||||
</h4>
|
||||
<div>
|
||||
<input id="markdown_escape_strings" class="text_pole textarea_compact" type="text" data-i18n="[placeholder]separate with commas w/o space between" placeholder="separate with commas w/o space between" maxlength="100" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<h4 data-i18n="Instruct mode">Instruct mode
|
||||
<a href="https://docs.sillytavern.app/usage/core-concepts/instructmode/" class="notes-link" target="_blank">
|
||||
<span class="note-link-span">?</span>
|
||||
@ -2040,18 +2081,26 @@
|
||||
<div class="flex-container">
|
||||
<div class="flex1">
|
||||
<label for="instruct_input_sequence">
|
||||
<span data-i18n="Input Sequence">Input Sequence</span>
|
||||
<small data-i18n="Input Sequence">Input Sequence</small>
|
||||
</label>
|
||||
<div>
|
||||
<textarea id="instruct_input_sequence" class="text_pole textarea_compact" type="text" maxlength="500" rows="1"></textarea>
|
||||
<textarea id="instruct_input_sequence" class="text_pole textarea_compact" maxlength="500" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
<label for="instruct_output_sequence">
|
||||
<span data-i18n="Output Sequence">Output Sequence</span>
|
||||
<small data-i18n="Output Sequence">Output Sequence</small>
|
||||
</label>
|
||||
<div>
|
||||
<textarea id="instruct_output_sequence" class="text_pole wide100p textarea_compact" type="text" maxlength="500" rows="1"></textarea>
|
||||
<textarea id="instruct_output_sequence" class="text_pole wide100p textarea_compact" maxlength="500" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
<label for="instruct_last_output_sequence">
|
||||
<small data-i18n="Last Sequence">Last Sequence</small>
|
||||
</label>
|
||||
<div>
|
||||
<textarea id="instruct_last_output_sequence" class="text_pole wide100p textarea_compact" maxlength="500" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -2061,7 +2110,7 @@
|
||||
<small data-i18n="System Sequence">System Sequence</small>
|
||||
</label>
|
||||
<div>
|
||||
<textarea id="instruct_system_sequence" class="text_pole textarea_compact" type="text" maxlength="500" rows="1"></textarea>
|
||||
<textarea id="instruct_system_sequence" class="text_pole textarea_compact" maxlength="500" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
@ -2069,7 +2118,7 @@
|
||||
<small data-i18n="Stop Sequence">Stop Sequence</small>
|
||||
</label>
|
||||
<div>
|
||||
<textarea id="instruct_stop_sequence" class="text_pole wide100p textarea_compact" type="text" maxlength="500" rows="1"></textarea>
|
||||
<textarea id="instruct_stop_sequence" class="text_pole wide100p textarea_compact" maxlength="500" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
@ -2077,14 +2126,22 @@
|
||||
<small data-i18n="Separator">Separator</small>
|
||||
</label>
|
||||
<div>
|
||||
<textarea id="instruct_separator_sequence" class="text_pole wide100p textarea_compact" type="text" maxlength="500" rows="1"></textarea>
|
||||
<textarea id="instruct_separator_sequence" class="text_pole wide100p textarea_compact" maxlength="500" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 data-i18n="Non-markdown strings">
|
||||
Non-markdown strings
|
||||
</h4>
|
||||
<div>
|
||||
<input id="markdown_escape_strings" class="text_pole textarea_compact" type="text" data-i18n="[placeholder]separate with commas w/o space between" placeholder="separate with commas w/o space between" maxlength="100" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div name="ContextFormatting" class="flex1">
|
||||
<h4><span data-i18n="Context Formatting">Context Formatting</span></h4>
|
||||
<div>
|
||||
<h4><span data-i18n="Tokenizer">Tokenizer</span>
|
||||
<a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#tokenizer" class="notes-link" target="_blank">
|
||||
@ -2128,19 +2185,19 @@
|
||||
Remove Empty New Lines from Output
|
||||
</span>
|
||||
</label>
|
||||
<div id="context-templates-block" class="template_element">
|
||||
<h4>
|
||||
Context Templates
|
||||
</h4>
|
||||
<div class="flex-container flexGap5">
|
||||
<select id="context_template" class="flex1 margin0">
|
||||
</select>
|
||||
<div id="context_template_new" class="menu_button fa-solid fa-plus margin0" title="Create new" data-i18n="[title]Create New"></div>
|
||||
<div id="context_template_edit" class="menu_button fa-solid fa-file-pen margin0" title="Edit" data-i18n="[title]Edit"></div>
|
||||
<div id="context_template_rename" class="menu_button fa-solid fa-i-cursor margin0" title="Rename" data-i18n="[title]Rename"></div>
|
||||
<div id="context_template_delete" class="menu_button fa-solid fa-trash-can margin0" title="Delete" data-i18n="[title]Delete"></div>
|
||||
</div>
|
||||
</div>
|
||||
<label class="checkbox_label" for="trim_spaces">
|
||||
<input id="trim_spaces" type="checkbox" />
|
||||
<span data-i18n="Trim spaces">Trim spaces</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="trim_sentences_checkbox">
|
||||
<input id="trim_sentences_checkbox" type="checkbox" />
|
||||
<span data-i18n="Trim Incomplete Sentences">Trim Incomplete Sentences</span>
|
||||
</label>
|
||||
<!-- Add margin since this is a child of above -->
|
||||
<label class="checkbox_label indent20p" for="include_newline_checkbox">
|
||||
<input id="include_newline_checkbox" type="checkbox" />
|
||||
<span data-i18n="Include Newline">Include Newline</span>
|
||||
</label>
|
||||
<div>
|
||||
<h4>
|
||||
<span data-i18n="Start Reply With">
|
||||
@ -2484,6 +2541,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="UI-language-block" class="flex-container flexFlowColumn">
|
||||
<h4>
|
||||
<span data-i18n="UI Language">UI Language</span>
|
||||
</h4>
|
||||
<div class="flex-container flexnowrap alignitemscenter">
|
||||
<select id="ui_language_select" class="margin0 margin-r5">
|
||||
<option value="" data-i18n="Browser default">
|
||||
Browser default
|
||||
</option>
|
||||
<option value="en">en</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="UI-presets-block" class="flex-container flexFlowColumn">
|
||||
<h4>
|
||||
<span data-i18n="UI Theme Preset">UI Theme Preset</span>
|
||||
@ -2920,6 +2990,7 @@
|
||||
<div id="rm_button_selected_ch">
|
||||
<h2></h2>
|
||||
</div>
|
||||
<i id="hideCharPanelAvatarButton" class="fa-solid fa-eye right_menu_button"></i>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end group peeking cope structure-->
|
||||
@ -2934,7 +3005,7 @@
|
||||
<input id="character_name_pole" name="ch_name" class="text_pole" data-i18n="[placeholder]Name this character" placeholder="Name this character" maxlength="50" value="" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div id="result_info" class="flex-container" title="Token counts may be inaccurate and provided just for reference." data-i18n="[title]Token counts may be inaccurate and provided just for reference."> </div>
|
||||
|
||||
|
||||
<div id="avatar_div" class="avatar_div alignitemsflexstart justifySpaceBetween flexnowrap flexGap5">
|
||||
<label id="avatar_div_div" class="add_avatar avatar" for="add_avatar_button" title="Click to select a new avatar for this character" data-i18n="[title]Click to select a new avatar for this character">
|
||||
@ -3007,6 +3078,7 @@
|
||||
|
||||
<div id="description_div" class="marginBot5">
|
||||
<span data-i18n="Character Description">Description</span>
|
||||
<div id="result_info" class="flex-container" title="Token counts may be inaccurate and provided just for reference." data-i18n="[title]Token counts may be inaccurate and provided just for reference."> </div>
|
||||
<a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#character-description" class="notes-link" target="_blank">
|
||||
<span class="note-link-span">?</span>
|
||||
</a>
|
||||
@ -3129,6 +3201,7 @@
|
||||
</div>
|
||||
<div class="inline-drawer-content">
|
||||
<div name="Current Group Members" class="flex-container flexFlowColumn overflowYAuto flex1">
|
||||
<div id="rm_group_members_pagination" class="group_pagination"></div>
|
||||
<div id="rm_group_members" class="overflowYAuto flex-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -3146,6 +3219,7 @@
|
||||
<div class="rm_tag_controls">
|
||||
<div class="tags rm_tag_filter"></div>
|
||||
</div>
|
||||
<div id="rm_group_add_members_pagination" class="group_pagination"></div>
|
||||
<div id="rm_group_add_members" class="overflowYAuto flex-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -3185,14 +3259,12 @@
|
||||
<div class="rm_tag_controls">
|
||||
<div class="tags rm_tag_filter"></div>
|
||||
</div>
|
||||
<!-- a div containing a dynamically updated count of characters currently displayed -->
|
||||
<div class="flex-container alignitemscenter">
|
||||
<div id="rm_character_count"></div>
|
||||
<i id="charListGridToggle" class="fa-solid fa-table-cells-large menu_button" title="Toggle character grid view"></i>
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
|
||||
<div id="rm_print_characters_pagination">
|
||||
<i id="charListGridToggle" class="fa-solid fa-table-cells-large menu_button" title="Toggle character grid view"></i>
|
||||
</div>
|
||||
<div id="rm_print_characters_block" class="flexFlowColumn"></div>
|
||||
</div>
|
||||
|
||||
@ -3331,6 +3403,7 @@
|
||||
|
||||
<div id="shadow_select_chat_popup">
|
||||
<div id="select_chat_popup">
|
||||
<input type="text" id="select_chat_search" placeholder="Search..." autocomplete="off">
|
||||
<div id="select_chat_import"> <!-- import chat popup header -->
|
||||
<div id="chat_import_button" class="fa-solid fa-file-arrow-up menu_button"></div>
|
||||
<div id="selectChatPopupHeaderText" class="TxtLrgBoldCenter">
|
||||
@ -3722,10 +3795,19 @@
|
||||
<input class="openai_logit_bias_text text_pole" data-i18n="[placeholder]Type here..." placeholder="type here..." />
|
||||
<input class="openai_logit_bias_value text_pole" type="number" min="-100" value="0" max="100" />
|
||||
<i class="menu_button fa-solid fa-xmark openai_logit_bias_remove"></i>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="novelai_logit_bias_template" class="template_element">
|
||||
<div class="novelai_logit_bias_form">
|
||||
<input class="novelai_logit_bias_text text_pole" data-i18n="[placeholder]Type here..." placeholder="type here..." />
|
||||
<input class="novelai_logit_bias_value text_pole" type="number" min="-2" value="0" max="2" step="0.01" />
|
||||
<i class="menu_button fa-solid fa-xmark novelai_logit_bias_remove"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="completion_prompt_manager_popup" class="drawer-content" style="display:none;">
|
||||
<div id="completion_prompt_manager_popup_inspect">
|
||||
<h3>Inspect</h3>
|
||||
@ -3774,7 +3856,7 @@
|
||||
<textarea id="completion_prompt_manager_popup_entry_form_prompt" class="text_pole" name="prompt">
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="completion_prompt_manager_popup_entry_form_footer" >
|
||||
<div class="completion_prompt_manager_popup_entry_form_footer">
|
||||
<a id="completion_prompt_manager_popup_entry_form_close" title="close" class="fa-solid fa-close menu_button"></a>
|
||||
<a id="completion_prompt_manager_popup_entry_form_reset" title="reset" class="fa-solid fa-undo menu_button"></a>
|
||||
<a id="completion_prompt_manager_popup_entry_form_save" title="save" class="fa-solid fa-save menu_button" data-pm-prompt=""></a>
|
||||
|
@ -5,6 +5,7 @@
|
||||
"stop_sequence": "",
|
||||
"input_sequence": "### Instruction:",
|
||||
"output_sequence": "### Response:",
|
||||
"last_output_sequence": "",
|
||||
"separator_sequence": "",
|
||||
"wrap": true
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"stop_sequence": "",
|
||||
"input_sequence": "USER: ",
|
||||
"output_sequence": "GPT: ",
|
||||
"last_output_sequence": "",
|
||||
"separator_sequence": "</s>",
|
||||
"wrap": false
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"stop_sequence": "",
|
||||
"input_sequence": "[INST]",
|
||||
"output_sequence": "[/INST]",
|
||||
"last_output_sequence": "",
|
||||
"separator_sequence": "\n",
|
||||
"wrap": false
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"stop_sequence": "</s>",
|
||||
"input_sequence": "<|user|>",
|
||||
"output_sequence": "<|model|>",
|
||||
"last_output_sequence": "",
|
||||
"separator_sequence": "",
|
||||
"wrap": false
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
"name": "OpenOrca/OpenChat",
|
||||
"names": true,
|
||||
"output_sequence": "<|end_of_turn|>\nAssistant: ",
|
||||
"last_output_sequence": "",
|
||||
"separator_sequence": "<|end_of_turn|>\n",
|
||||
"stop_sequence": "",
|
||||
"system_prompt": "You are a helpful assistant. Please answer truthfully and write out your thinking step by step to be sure you get the right answer. If you make a mistake or encounter an error in your thinking, say so out loud and attempt to correct it. If you don't know or aren't sure about something, say so clearly. You will act as a professional logician, mathematician, and physicist. You will also act as the most appropriate type of expert to answer any particular question or solve the relevant problem; state which expert type your are, if so. Also think of any particular named expert that would be ideal to answer the relevant question or solve the relevant problem; name and act as them, if appropriate.\n",
|
||||
|
@ -1,12 +1,13 @@
|
||||
{
|
||||
"input_sequence": "### Instruction:",
|
||||
"last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):",
|
||||
"macro": true,
|
||||
"name": "Roleplay",
|
||||
"names": true,
|
||||
"output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):",
|
||||
"output_sequence": "### Response:",
|
||||
"separator_sequence": "",
|
||||
"stop_sequence": "",
|
||||
"system_prompt": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.\n\nAvoid repetition, don't loop. Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions.\n\n### Input:",
|
||||
"system_prompt": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.\n\nAvoid repetition, don't loop. Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions.",
|
||||
"system_sequence": "",
|
||||
"wrap": true
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"stop_sequence": "",
|
||||
"input_sequence": "### Human:",
|
||||
"output_sequence": "### Assistant:",
|
||||
"last_output_sequence": "",
|
||||
"separator_sequence": "",
|
||||
"wrap": true
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"stop_sequence": "",
|
||||
"input_sequence": "USER: ",
|
||||
"output_sequence": "ASSISTANT: ",
|
||||
"last_output_sequence": "",
|
||||
"separator_sequence": "</s>",
|
||||
"wrap": false
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"stop_sequence": "",
|
||||
"input_sequence": "USER: ",
|
||||
"output_sequence": "ASSISTANT: ",
|
||||
"last_output_sequence": "",
|
||||
"separator_sequence": "",
|
||||
"wrap": true
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"stop_sequence": "",
|
||||
"input_sequence": "",
|
||||
"output_sequence": "### Response:",
|
||||
"last_output_sequence": "",
|
||||
"separator_sequence": "</s>",
|
||||
"wrap": true
|
||||
}
|
||||
}
|
||||
|
13
public/instruct/simple-proxy-for-tavern.json
Normal file
13
public/instruct/simple-proxy-for-tavern.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"input_sequence": "### Instruction:\n#### {{user}}:",
|
||||
"last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):\n#### {{char}}:",
|
||||
"macro": true,
|
||||
"name": "simple-proxy-for-tavern",
|
||||
"names": false,
|
||||
"output_sequence": "### Response:\n#### {{char}}:",
|
||||
"separator_sequence": "",
|
||||
"stop_sequence": "",
|
||||
"system_prompt": "## {{char}}\n- You're \"{{char}}\" in this never-ending roleplay with \"{{user}}\".",
|
||||
"system_sequence": "",
|
||||
"wrap": true
|
||||
}
|
662
public/script.js
662
public/script.js
File diff suppressed because it is too large
Load Diff
@ -172,7 +172,7 @@ function PromptManagerModule() {
|
||||
strategy: 'global',
|
||||
dummyId: 100000
|
||||
},
|
||||
draggable: true,
|
||||
sortableDelay: 30,
|
||||
warningTokenThreshold: 1500,
|
||||
dangerTokenThreshold: 500,
|
||||
defaultPrompts: {
|
||||
@ -181,10 +181,7 @@ function PromptManagerModule() {
|
||||
jailbreak: '',
|
||||
enhanceDefinitions: ''
|
||||
}
|
||||
}
|
||||
|
||||
// Either 0 for done or 1 for rendering
|
||||
this.renderState = 0;
|
||||
};
|
||||
|
||||
// Chatcompletion configuration object
|
||||
this.serviceSettings = null;
|
||||
@ -591,22 +588,12 @@ PromptManagerModule.prototype.init = function (moduleConfiguration, serviceSetti
|
||||
* @param afterTryGenerate - Whether a dry run should be attempted before rendering
|
||||
*/
|
||||
PromptManagerModule.prototype.render = function (afterTryGenerate = true) {
|
||||
if (main_api !== 'openai' ||
|
||||
null === this.activeCharacter ||
|
||||
1 === this.renderState) return;
|
||||
if (main_api !== 'openai') return;
|
||||
|
||||
this.renderState = 1;
|
||||
if (null === this.activeCharacter) return;
|
||||
this.error = null;
|
||||
|
||||
const stopPropagation = (event) => {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
const configurationContainer = document.getElementById('ai_response_configuration');
|
||||
try {
|
||||
// Lock configuration during render
|
||||
configurationContainer.addEventListener('click', stopPropagation, true);
|
||||
|
||||
waitUntilCondition(() => !is_send_press && !is_group_generating, 1024 * 1024, 100).then(() => {
|
||||
if (true === afterTryGenerate) {
|
||||
// Executed during dry-run for determining context composition
|
||||
this.profileStart('filling context');
|
||||
@ -626,15 +613,9 @@ PromptManagerModule.prototype.render = function (afterTryGenerate = true) {
|
||||
this.makeDraggable();
|
||||
this.profileEnd('render');
|
||||
}
|
||||
} catch (error) {
|
||||
this.log('----- Unexpected error while rendering prompt manager -----');
|
||||
this.log(error);
|
||||
this.log(error.stack);
|
||||
this.log('-----------------------------------------------------------');
|
||||
} finally {
|
||||
this.renderState = 0;
|
||||
configurationContainer.removeEventListener('click', stopPropagation, true);
|
||||
}
|
||||
}).catch(() => {
|
||||
console.log('Timeout while waiting for send press to be false');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -889,7 +870,7 @@ PromptManagerModule.prototype.handleGroupSelected = function (event) {
|
||||
*/
|
||||
PromptManagerModule.prototype.getActiveGroupCharacters = function() {
|
||||
// ToDo: Ideally, this should return the actual characters.
|
||||
return (this.activeCharacter?.group?.members || []).map(member => member.substring(0, member.lastIndexOf('.')));
|
||||
return (this.activeCharacter?.group?.members || []).map(member => member && member.substring(0, member.lastIndexOf('.')));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1588,6 +1569,7 @@ PromptManagerModule.prototype.getFormattedDate = function() {
|
||||
*/
|
||||
PromptManagerModule.prototype.makeDraggable = function () {
|
||||
$(`#${this.configuration.prefix}prompt_manager_list`).sortable({
|
||||
delay: this.configuration.sortableDelay,
|
||||
items: `.${this.configuration.prefix}prompt_manager_prompt_draggable`,
|
||||
update: ( event, ui ) => {
|
||||
const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter);
|
||||
|
@ -13,11 +13,13 @@ import {
|
||||
menu_type,
|
||||
max_context,
|
||||
saveSettingsDebounced,
|
||||
eventSource,
|
||||
active_group,
|
||||
active_character,
|
||||
setActiveGroup,
|
||||
setActiveCharacter,
|
||||
getEntitiesList,
|
||||
getThumbnailUrl,
|
||||
selectCharacterById,
|
||||
} from "../script.js";
|
||||
|
||||
import {
|
||||
@ -348,12 +350,13 @@ async function RA_autoloadchat() {
|
||||
// active character is the name, we should look it up in the character list and get the id
|
||||
let active_character_id = Object.keys(characters).find(key => characters[key].avatar === active_character);
|
||||
|
||||
var charToAutoLoad = document.getElementById('CharID' + active_character_id);
|
||||
let groupToAutoLoad = document.querySelector(`.group_select[grid="${active_group}"]`);
|
||||
if (charToAutoLoad != null) {
|
||||
$(charToAutoLoad).click();
|
||||
if (active_character_id !== null) {
|
||||
selectCharacterById(String(active_character_id));
|
||||
}
|
||||
else if (groupToAutoLoad != null) {
|
||||
|
||||
let groupToAutoLoad = document.querySelector(`.group_select[grid="${active_group}"]`);
|
||||
|
||||
if (groupToAutoLoad != null) {
|
||||
$(groupToAutoLoad).click();
|
||||
}
|
||||
|
||||
@ -362,53 +365,60 @@ async function RA_autoloadchat() {
|
||||
}
|
||||
|
||||
export async function favsToHotswap() {
|
||||
const selector = ['#rm_print_characters_block .character_select', '#rm_print_characters_block .group_select'].join(',');
|
||||
const entities = getEntitiesList({ doFilter: false });
|
||||
const container = $('#right-nav-panel .hotswap');
|
||||
const template = $('#hotswap_template .hotswapAvatar');
|
||||
container.empty();
|
||||
const maxCount = 6;
|
||||
let count = 0;
|
||||
|
||||
$(selector).sort(sortByCssOrder).each(function () {
|
||||
if ($(this).hasClass('is_fav') && count < maxCount) {
|
||||
const isCharacter = $(this).hasClass('character_select');
|
||||
const isGroup = $(this).hasClass('group_select');
|
||||
const grid = Number($(this).attr('grid'));
|
||||
const chid = Number($(this).attr('chid'));
|
||||
let thisHotSwapSlot = template.clone();
|
||||
thisHotSwapSlot.toggleClass('character_select', isCharacter);
|
||||
thisHotSwapSlot.toggleClass('group_select', isGroup);
|
||||
thisHotSwapSlot.attr('grid', isGroup ? grid : '');
|
||||
thisHotSwapSlot.attr('chid', isCharacter ? chid : '');
|
||||
thisHotSwapSlot.data('id', isGroup ? grid : chid);
|
||||
thisHotSwapSlot.attr('title', '');
|
||||
|
||||
if (isGroup) {
|
||||
const group = groups.find(x => x.id === grid);
|
||||
const avatar = getGroupAvatar(group);
|
||||
$(thisHotSwapSlot).find('img').replaceWith(avatar);
|
||||
}
|
||||
|
||||
if (isCharacter) {
|
||||
const avatarUrl = $(this).find('img').attr('src');
|
||||
$(thisHotSwapSlot).find('img').attr('src', avatarUrl);
|
||||
}
|
||||
|
||||
$(thisHotSwapSlot).css('cursor', 'pointer');
|
||||
container.append(thisHotSwapSlot);
|
||||
count++;
|
||||
for (const entity of entities) {
|
||||
if (count >= maxCount) {
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
//console.log('about to check for leftover selectors...')
|
||||
const isFavorite = entity.item.fav || entity.item.fav == 'true';
|
||||
|
||||
if (!isFavorite) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const isCharacter = entity.type === 'character';
|
||||
const isGroup = entity.type === 'group';
|
||||
|
||||
const grid = isGroup ? entity.id : '';
|
||||
const chid = isCharacter ? entity.id : '';
|
||||
|
||||
let slot = template.clone();
|
||||
slot.toggleClass('character_select', isCharacter);
|
||||
slot.toggleClass('group_select', isGroup);
|
||||
slot.attr('grid', isGroup ? grid : '');
|
||||
slot.attr('chid', isCharacter ? chid : '');
|
||||
slot.data('id', isGroup ? grid : chid);
|
||||
slot.attr('title', '');
|
||||
|
||||
if (isGroup) {
|
||||
const group = groups.find(x => x.id === grid);
|
||||
const avatar = getGroupAvatar(group);
|
||||
$(slot).find('img').replaceWith(avatar);
|
||||
}
|
||||
|
||||
if (isCharacter) {
|
||||
const avatarUrl = getThumbnailUrl('avatar', entity.item.avatar);
|
||||
$(slot).find('img').attr('src', avatarUrl);
|
||||
}
|
||||
|
||||
$(slot).css('cursor', 'pointer');
|
||||
container.append(slot);
|
||||
count++;
|
||||
}
|
||||
|
||||
// there are 6 slots in total,
|
||||
if (count < maxCount) { //if any are left over
|
||||
let leftOverSlots = maxCount - count;
|
||||
for (let i = 1; i <= leftOverSlots; i++) {
|
||||
container.append(template.clone());
|
||||
}
|
||||
} else {
|
||||
//console.log(`count was ${count} so no need to knock off any selectors!`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,214 +0,0 @@
|
||||
import {
|
||||
callPopup,
|
||||
getRequestHeaders,
|
||||
saveSettingsDebounced,
|
||||
} from '../script.js';
|
||||
import { debounce } from './utils.js';
|
||||
|
||||
export let context_templates = [];
|
||||
export let context_settings = {
|
||||
selected_template: '',
|
||||
};
|
||||
|
||||
const saveTemplateDebounced = debounce((name) => alert('implement me', name), 2000);
|
||||
|
||||
export function loadContextTemplatesFromSettings(data, settings) {
|
||||
context_templates = data.context || [];
|
||||
context_settings = Object.assign(context_settings, (settings.context_settings || {}));
|
||||
|
||||
const dropdown = $('#context_template');
|
||||
dropdown.empty();
|
||||
dropdown.append('<option value="">-- None --</option>')
|
||||
|
||||
for (const template of context_templates) {
|
||||
const name = template.name;
|
||||
const option = document.createElement('option');
|
||||
option.innerText = name;
|
||||
option.value = name;
|
||||
option.selected = context_settings.selected_template == name;
|
||||
dropdown.append(option);
|
||||
}
|
||||
}
|
||||
|
||||
function onContextTemplateChange() {
|
||||
const value = $(this).find(':selected').val();
|
||||
context_settings.selected_template = value;
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
function openContextTemplateEditor() {
|
||||
const template = context_templates.find(x => x.name == context_settings.selected_template);
|
||||
|
||||
if (!template || !context_settings.selected_template) {
|
||||
toastr.info('No context template selected');
|
||||
return;
|
||||
}
|
||||
|
||||
const editor = $('#context_editor_template .context_editor').clone();
|
||||
const injectionsContainer = editor.find('.chat_injections_list');
|
||||
editor.find('.template_name').text(template.name);
|
||||
editor.find('.story_string_template').text(template.storyString).on('input', function () {
|
||||
const value = $(this).val();
|
||||
template.storyString = value;
|
||||
saveTemplateDebounced(template.name);
|
||||
});
|
||||
editor.find('.chat_injection_add').on('click', function () {
|
||||
const injection = { id: Date.now(), text: '', depth: 0 };
|
||||
template.injections.push(injection);
|
||||
addChatInjection(injectionsContainer, injection, template);
|
||||
saveTemplateDebounced(template.name);
|
||||
});
|
||||
|
||||
for (const injection of template.injections) {
|
||||
addChatInjection(injectionsContainer, injection, template);
|
||||
}
|
||||
|
||||
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
|
||||
callPopup(editor, 'text');
|
||||
}
|
||||
|
||||
async function onRenameContextTemplateClick() {
|
||||
const oldName = context_settings.selected_template;
|
||||
const newName = await inputTemplateName();
|
||||
const template = context_templates.find(x => x.name === oldName);
|
||||
|
||||
if (!template || !newName || oldName === newName) {
|
||||
return;
|
||||
}
|
||||
|
||||
await saveContextTemplate(newName);
|
||||
context_settings.selected_template = newName;
|
||||
saveSettingsDebounced();
|
||||
await deleteContextTemplate(oldName);
|
||||
toastr.success('Context template renamed', newName);
|
||||
}
|
||||
|
||||
async function deleteContextTemplate(name) {
|
||||
const response = await fetch('/delete_context_template', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({ name }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Context template not deleted');
|
||||
}
|
||||
}
|
||||
|
||||
async function saveContextTemplate(name) {
|
||||
const template = context_templates.find(x => x.name === name);
|
||||
|
||||
if (!template) {
|
||||
throw new Error(`Context template not found: ${name}`);
|
||||
}
|
||||
|
||||
const response = await fetch('/save_context_template', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({ name, template }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Context template not saved');
|
||||
}
|
||||
}
|
||||
|
||||
async function inputTemplateName() {
|
||||
let name = await callPopup('Enter a template name:', 'input');
|
||||
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
name = DOMPurify.sanitize(name.trim());
|
||||
|
||||
if (context_templates.findIndex(x => x.name == name) > -1) {
|
||||
toastr.warning('Template with that name already exists', 'Pick a unique name');
|
||||
return false;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
function addChatInjection(container, model, parent) {
|
||||
const template = $('#chat_injection_template .chat_injection').clone();
|
||||
template.attr('id', model.id);
|
||||
template.find('.chat_injection_text').val(model.text).on('input', function () {
|
||||
const value = $(this).val();
|
||||
model.text = value;
|
||||
saveTemplateDebounced(parent.name);
|
||||
});
|
||||
template.find('.chat_injection_depth').val(model.depth).on('input', function () {
|
||||
const value = Math.abs(Number($(this).val()));
|
||||
model.depth = value;
|
||||
saveTemplateDebounced(parent.name);
|
||||
});
|
||||
template.find('.chat_injection_remove').on('click', function () {
|
||||
if (!confirm('Are you sure?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = parent.injections.findIndex(x => x == model);
|
||||
|
||||
if (index === -1) {
|
||||
console.error('Does not compute, injection index was lost');
|
||||
return;
|
||||
}
|
||||
|
||||
parent.injections.splice(index, 1);
|
||||
template.remove();
|
||||
saveTemplateDebounced(parent.name);
|
||||
});
|
||||
container.append(template);
|
||||
}
|
||||
|
||||
function copyTemplateParameter(event) {
|
||||
const text = $(event.target).text();
|
||||
navigator.clipboard.writeText(text);
|
||||
toastr.info('Copied!', '', { timeOut: 2000 });
|
||||
}
|
||||
|
||||
async function onNewContextTemplateClick() {
|
||||
const name = await inputTemplateName();
|
||||
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
const template = { name: name, injections: [], storyString: '' };
|
||||
context_templates.push(template);
|
||||
const option = document.createElement('option');
|
||||
option.innerText = name;
|
||||
option.value = name;
|
||||
option.selected = true;
|
||||
$('#context_template').append(option).val(name).trigger('change');
|
||||
saveTemplateDebounced(name);
|
||||
}
|
||||
|
||||
async function onDeleteContextTemplateClick() {
|
||||
const template = context_templates.find(x => x.name == context_settings.selected_template);
|
||||
|
||||
if (!template || !context_settings.selected_template) {
|
||||
toastr.info('No context template selected');
|
||||
return;
|
||||
}
|
||||
|
||||
const confirm = await callPopup('Are you sure?', 'confirm');
|
||||
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
await deleteContextTemplate(context_settings.selected_template);
|
||||
$(`#context_template option[value="${context_settings.selected_template}"]`).remove();
|
||||
$('#context_template').trigger('change');
|
||||
}
|
||||
|
||||
jQuery(() => {
|
||||
$('#context_template_edit').on('click', openContextTemplateEditor);
|
||||
$('#context_template').on('change', onContextTemplateChange);
|
||||
$('#context_template_new').on('click', onNewContextTemplateClick);
|
||||
$('#context_template_rename').on('click', onRenameContextTemplateClick);
|
||||
$('#context_template_delete').on('click', onDeleteContextTemplateClick);
|
||||
$(document).on('pointerup', '.template_parameters_list code', copyTemplateParameter);
|
||||
})
|
@ -8,6 +8,11 @@ const MODULE_NAME = 'backgrounds';
|
||||
const METADATA_KEY = 'custom_background';
|
||||
const UPDATE_INTERVAL = 1000;
|
||||
|
||||
function forceSetBackground(background) {
|
||||
saveBackgroundMetadata(background);
|
||||
setCustomBackground();
|
||||
}
|
||||
|
||||
async function moduleWorker() {
|
||||
if (hasCustomBackground()) {
|
||||
$('#unlock_background').show();
|
||||
@ -167,4 +172,5 @@ $(document).ready(function () {
|
||||
registerSlashCommand('lockbg', onLockBackgroundClick, ['bglock'], " – locks a background for the currently selected chat", true, true);
|
||||
registerSlashCommand('unlockbg', onUnlockBackgroundClick, ['bgunlock'], ' – unlocks a background for the currently selected chat', true, true);
|
||||
registerSlashCommand('autobg', autoBackgroundCommand, ['bgauto'], ' – automatically changes the background based on the chat context using the AI request prompt', true, true);
|
||||
window['forceSetBackground'] = forceSetBackground;
|
||||
});
|
||||
|
@ -48,7 +48,7 @@
|
||||
z-index: 2;
|
||||
overflow: hidden;
|
||||
resize: both;
|
||||
|
||||
display: flex;
|
||||
}
|
||||
|
||||
img.expression {
|
||||
@ -56,7 +56,6 @@ img.expression {
|
||||
min-height: 100px;
|
||||
max-height: 90vh;
|
||||
max-width: 90vh;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
padding: 0;
|
||||
@ -181,4 +180,4 @@ img.expression.default {
|
||||
div.expression {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -597,8 +597,8 @@ function doAutoAdjust(chat, maxContext) {
|
||||
console.debug('CHROMADB: Mean message length (tokens): %o', meanMessageLengthTokens);
|
||||
// Get number of messages in context
|
||||
const contextMessages = Math.max(1, Math.ceil(maxContext / meanMessageLengthTokens));
|
||||
// Round up to nearest 10
|
||||
const contextMessagesRounded = Math.ceil(contextMessages / 10) * 10;
|
||||
// Round up to nearest 5
|
||||
const contextMessagesRounded = Math.ceil(contextMessages / 5) * 5;
|
||||
console.debug('CHROMADB: Estimated context messages (rounded): %o', contextMessagesRounded);
|
||||
// Messages to keep (proportional, rounded to nearest 5, minimum 5, maximum 500)
|
||||
const messagesToKeep = Math.min(defaultSettings.keep_context_max, Math.max(5, Math.floor(contextMessagesRounded * extension_settings.chromadb.keep_context_proportion / 5) * 5));
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { callPopup, eventSource, event_types, getCurrentChatId, reloadCurrentChat, saveSettingsDebounced } from "../../../script.js";
|
||||
import { callPopup, getCurrentChatId, reloadCurrentChat, saveSettingsDebounced } from "../../../script.js";
|
||||
import { extension_settings } from "../../extensions.js";
|
||||
import { uuidv4, waitUntilCondition } from "../../utils.js";
|
||||
import { getSortableDelay, uuidv4 } from "../../utils.js";
|
||||
import { regex_placement } from "./engine.js";
|
||||
|
||||
async function saveRegexScript(regexScript, existingScriptIndex) {
|
||||
@ -236,6 +236,7 @@ jQuery(async () => {
|
||||
});
|
||||
|
||||
$('#saved_regex_scripts').sortable({
|
||||
delay: getSortableDelay(),
|
||||
stop: function () {
|
||||
let newScripts = [];
|
||||
$('#saved_regex_scripts').children().each(function () {
|
||||
|
@ -1,65 +1,40 @@
|
||||
/*
|
||||
TODO:
|
||||
- Allow to upload RVC model to extras server ?
|
||||
- Settings per characters ?
|
||||
- load RVC models list from extras
|
||||
- Settings per characters
|
||||
*/
|
||||
|
||||
import { saveSettingsDebounced } from "../../../script.js";
|
||||
import { getContext, getApiUrl, extension_settings, doExtrasFetch } from "../../extensions.js";
|
||||
export { MODULE_NAME, rvcVoiceConversion};
|
||||
import { getContext, getApiUrl, extension_settings, doExtrasFetch, ModuleWorkerWrapper, modules } from "../../extensions.js";
|
||||
export { MODULE_NAME, rvcVoiceConversion };
|
||||
|
||||
const MODULE_NAME = 'RVC';
|
||||
const DEBUG_PREFIX = "<RVC module> "
|
||||
const UPDATE_INTERVAL = 1000
|
||||
|
||||
// Send an audio file to RVC to convert voice
|
||||
async function rvcVoiceConversion(response, character) {
|
||||
let apiResult
|
||||
let charactersList = [] // Updated with module worker
|
||||
let rvcModelsList = [] // Initialized only once
|
||||
let rvcModelsReceived = false;
|
||||
|
||||
// Check voice map
|
||||
if (extension_settings.rvc.voiceMap[character] === undefined) {
|
||||
toastr.error("No model is assigned to character '"+character+"', check RVC voice map in the extension menu.", DEBUG_PREFIX+'RVC Voice map error', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
console.error("No RVC model assign in voice map for current character "+character);
|
||||
return response;
|
||||
function updateVoiceMapText() {
|
||||
let voiceMapText = ""
|
||||
for (let i in extension_settings.rvc.voiceMap) {
|
||||
const voice_settings = extension_settings.rvc.voiceMap[i];
|
||||
voiceMapText += i + ":"
|
||||
+ voice_settings["modelName"] + "("
|
||||
+ voice_settings["pitchExtraction"] + ","
|
||||
+ voice_settings["pitchOffset"] + ","
|
||||
+ voice_settings["indexRate"] + ","
|
||||
+ voice_settings["filterRadius"] + ","
|
||||
+ voice_settings["rmsMixRate"] + ","
|
||||
+ voice_settings["protect"]
|
||||
+ "),\n"
|
||||
}
|
||||
|
||||
// Load model if different from currently loaded
|
||||
//if (currentModel === null | currentModel != extension_settings.rvc.voiceMap[character])
|
||||
// await rvcLoadModel(extension_settings.rvc.voiceMap[character]);
|
||||
extension_settings.rvc.voiceMapText = voiceMapText;
|
||||
$('#rvc_voice_map').val(voiceMapText);
|
||||
|
||||
const audioData = await response.blob()
|
||||
if (!audioData.type in ['audio/mpeg', 'audio/wav', 'audio/x-wav', 'audio/wave', 'audio/webm']) {
|
||||
throw `TTS received HTTP response with invalid data format. Expecting audio/mpeg, got ${audioData.type}`
|
||||
}
|
||||
console.log("Audio type received:",audioData.type)
|
||||
|
||||
console.log("Sending tts audio data to RVC on extras server")
|
||||
|
||||
var requestData = new FormData();
|
||||
requestData.append('AudioFile', audioData, 'record');
|
||||
requestData.append("json", JSON.stringify({
|
||||
"modelName": extension_settings.rvc.voiceMap[character],
|
||||
"pitchOffset": extension_settings.rvc.pitchOffset,
|
||||
"pitchExtraction": extension_settings.rvc.pitchExtraction,
|
||||
"indexRate": extension_settings.rvc.indexRate,
|
||||
"filterRadius": extension_settings.rvc.filterRadius,
|
||||
//"rmsMixRate": extension_settings.rvc.rmsMixRate,
|
||||
"protect": extension_settings.rvc.protect
|
||||
}));
|
||||
|
||||
const url = new URL(getApiUrl());
|
||||
url.pathname = '/api/voice-conversion/rvc/process-audio';
|
||||
|
||||
apiResult = await doExtrasFetch(url, {
|
||||
method: 'POST',
|
||||
body: requestData,
|
||||
});
|
||||
|
||||
if (!apiResult.ok) {
|
||||
toastr.error(apiResult.statusText, DEBUG_PREFIX+' RVC Voice Conversion Failed', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`);
|
||||
}
|
||||
|
||||
return apiResult;
|
||||
console.debug(DEBUG_PREFIX, "Updated voice map debug text to\n", voiceMapText)
|
||||
}
|
||||
|
||||
//#############################//
|
||||
@ -68,13 +43,13 @@ async function rvcVoiceConversion(response, character) {
|
||||
|
||||
const defaultSettings = {
|
||||
enabled: false,
|
||||
model:"",
|
||||
pitchOffset:0,
|
||||
pitchExtraction:"dio",
|
||||
indexRate:0.88,
|
||||
filterRadius:3,
|
||||
//rmsMixRate:1,
|
||||
protect:0.33,
|
||||
model: "",
|
||||
pitchOffset: 0,
|
||||
pitchExtraction: "dio",
|
||||
indexRate: 0.88,
|
||||
filterRadius: 3,
|
||||
rmsMixRate: 1,
|
||||
protect: 0.33,
|
||||
voicMapText: "",
|
||||
voiceMap: {}
|
||||
}
|
||||
@ -83,12 +58,9 @@ function loadSettings() {
|
||||
if (Object.keys(extension_settings.rvc).length === 0) {
|
||||
Object.assign(extension_settings.rvc, defaultSettings)
|
||||
}
|
||||
$('#rvc_enabled').prop('checked',extension_settings.rvc.enabled);
|
||||
$('#rvc_enabled').prop('checked', extension_settings.rvc.enabled);
|
||||
$('#rvc_model').val(extension_settings.rvc.model);
|
||||
|
||||
$('#rvc_pitch_offset').val(extension_settings.rvc.pitchOffset);
|
||||
$('#rvc_pitch_offset_value').text(extension_settings.rvc.pitchOffset);
|
||||
|
||||
$('#rvc_pitch_extraction').val(extension_settings.rvc.pitchExtraction);
|
||||
$('#rvc_pitch_extractiont_value').text(extension_settings.rvc.pitchExtraction);
|
||||
|
||||
@ -98,42 +70,17 @@ function loadSettings() {
|
||||
$('#rvc_filter_radius').val(extension_settings.rvc.filterRadius);
|
||||
$("#rvc_filter_radius_value").text(extension_settings.rvc.filterRadius);
|
||||
|
||||
//$('#rvc_mix_rate').val(extension_settings.rvc.rmsMixRate);
|
||||
$('#rvc_pitch_offset').val(extension_settings.rvc.pitchOffset);
|
||||
$('#rvc_pitch_offset_value').text(extension_settings.rvc.pitchOffset);
|
||||
|
||||
$('#rvc_rms_mix_rate').val(extension_settings.rvc.rmsMixRate);
|
||||
$("#rvc_rms_mix_rate_value").text(extension_settings.rvc.rmsMixRate);
|
||||
|
||||
$('#rvc_protect').val(extension_settings.rvc.protect);
|
||||
$("#rvc_protect_value").text(extension_settings.rvc.protect);
|
||||
|
||||
$('#rvc_voice_map').val(extension_settings.rvc.voiceMapText);
|
||||
}
|
||||
|
||||
async function onApplyClick() {
|
||||
let error = false;
|
||||
let array = $('#rvc_voice_map').val().split(",");
|
||||
array = array.map(element => {return element.trim();});
|
||||
array = array.filter((str) => str !== '');
|
||||
extension_settings.rvc.voiceMap = {};
|
||||
for (const text of array) {
|
||||
if (text.includes(":")) {
|
||||
const pair = text.split(":")
|
||||
extension_settings.rvc.voiceMap[pair[0].trim()] = pair[1].trim()
|
||||
console.debug(DEBUG_PREFIX+"Added mapping", pair[0],"=>", extension_settings.rvc.voiceMap[pair[0]]);
|
||||
}
|
||||
else {
|
||||
$("#rvc_status").text("Voice map is invalid, check console for errors");
|
||||
$("#rvc_status").css("color", "red");
|
||||
console.error(DEBUG_PREFIX,"Wrong syntax for message mapping, no ':' found in:", text);
|
||||
toastr.error("no ':' found in: '"+text+"'", DEBUG_PREFIX+' RVC Voice map error', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
$("#rvc_status").text("Successfully applied settings");
|
||||
$("#rvc_status").css("color", "green");
|
||||
console.debug(DEBUG_PREFIX+"Updated message mapping", extension_settings.rvc.voiceMap);
|
||||
toastr.info("New map:\n"+JSON.stringify(extension_settings.rvc.voiceMap).substring(0,200)+"...", DEBUG_PREFIX+"Updated message mapping", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
extension_settings.rvc.voiceMapText = $('#rvc_voice_map').val();
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
}
|
||||
|
||||
async function onEnabledClick() {
|
||||
@ -164,12 +111,93 @@ async function onPitchOffsetChange() {
|
||||
saveSettingsDebounced()
|
||||
}
|
||||
|
||||
async function onRmsMixRateChange() {
|
||||
extension_settings.rvc.rmsMixRate = Number($('#rvc_rms_mix_rate').val());
|
||||
$("#rvc_rms_mix_rate_value").text(extension_settings.rvc.rmsMixRate)
|
||||
saveSettingsDebounced()
|
||||
}
|
||||
|
||||
async function onProtectChange() {
|
||||
extension_settings.rvc.protect = Number($('#rvc_protect').val());
|
||||
$("#rvc_protect_value").text(extension_settings.rvc.protect)
|
||||
saveSettingsDebounced()
|
||||
}
|
||||
|
||||
async function onApplyClick() {
|
||||
let error = false;
|
||||
const character = $("#rvc_character_select").val();
|
||||
const model_name = $("#rvc_model_select").val();
|
||||
const pitchExtraction = $("#rvc_pitch_extraction").val();
|
||||
const indexRate = $("#rvc_index_rate").val();
|
||||
const filterRadius = $("#rvc_filter_radius").val();
|
||||
const pitchOffset = $("#rvc_pitch_offset").val();
|
||||
const rmsMixRate = $("#rvc_rms_mix_rate").val();
|
||||
const protect = $("#rvc_protect").val();
|
||||
|
||||
if (character === "none") {
|
||||
toastr.error("Character not selected.", DEBUG_PREFIX + " voice mapping apply", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (model_name == "none") {
|
||||
toastr.error("Model not selected.", DEBUG_PREFIX + " voice mapping apply", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
return;
|
||||
}
|
||||
|
||||
extension_settings.rvc.voiceMap[character] = {
|
||||
"modelName": model_name,
|
||||
"pitchExtraction": pitchExtraction,
|
||||
"indexRate": indexRate,
|
||||
"filterRadius": filterRadius,
|
||||
"pitchOffset": pitchOffset,
|
||||
"rmsMixRate": rmsMixRate,
|
||||
"protect": protect
|
||||
}
|
||||
|
||||
updateVoiceMapText();
|
||||
|
||||
console.debug(DEBUG_PREFIX, "Updated settings of ", character, ":", extension_settings.rvc.voiceMap[character])
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
async function onDeleteClick() {
|
||||
const character = $("#rvc_character_select").val();
|
||||
|
||||
if (character === "none") {
|
||||
toastr.error("Character not selected.", DEBUG_PREFIX + " voice mapping delete", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
return;
|
||||
}
|
||||
|
||||
delete extension_settings.rvc.voiceMap[character];
|
||||
console.debug(DEBUG_PREFIX, "Deleted settings of ", character);
|
||||
updateVoiceMapText();
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
async function onClickUpload() {
|
||||
const url = new URL(getApiUrl());
|
||||
const inputFiles = $("#rvc_model_upload_file").get(0).files;
|
||||
let formData = new FormData();
|
||||
|
||||
for (const file of inputFiles)
|
||||
formData.append(file.name, file);
|
||||
|
||||
console.debug(DEBUG_PREFIX, "Sending files:", formData);
|
||||
url.pathname = '/api/voice-conversion/rvc/upload-models';
|
||||
|
||||
const apiResult = await doExtrasFetch(url, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!apiResult.ok) {
|
||||
toastr.error(apiResult.statusText, DEBUG_PREFIX + ' Check extras console for errors log');
|
||||
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`);
|
||||
}
|
||||
|
||||
alert('The file has been uploaded successfully.');
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
function addExtensionControls() {
|
||||
const settingsHtml = `
|
||||
@ -185,8 +213,28 @@ $(document).ready(function () {
|
||||
<input type="checkbox" id="rvc_enabled" name="rvc_enabled">
|
||||
<small>Enabled</small>
|
||||
</label>
|
||||
<label>Voice Map (debug infos)</label>
|
||||
<textarea id="rvc_voice_map" type="text" class="text_pole textarea_compact" rows="4"
|
||||
placeholder="Voice map will appear here for debug purpose"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label for="rvc_character_select">Character:</label>
|
||||
<select id="rvc_character_select">
|
||||
<!-- Populated by JS -->
|
||||
</select>
|
||||
<label for="rvc_model_select">Voice:</label>
|
||||
<select id="rvc_model_select">
|
||||
<!-- Populated by JS -->
|
||||
</select>
|
||||
<div>
|
||||
<label for="rvc_model_upload_file">Select models to upload (zip files)</label>
|
||||
<input
|
||||
type="file"
|
||||
id="rvc_model_upload_file"
|
||||
accept=".zip,.rar,.7zip,.7z" multiple />
|
||||
<button id="rvc_model_upload_button"> Upload </button>
|
||||
<button id="rvc_model_refresh_button"> Refresh Voices </button>
|
||||
</div>
|
||||
<span>Select Pitch Extraction</span> </br>
|
||||
<select id="rvc_pitch_extraction">
|
||||
<option value="dio">dio</option>
|
||||
@ -194,9 +242,8 @@ $(document).ready(function () {
|
||||
<option value="harvest">harvest</option>
|
||||
<option value="torchcrepe">torchcrepe</option>
|
||||
<option value="rmvpe">rmvpe</option>
|
||||
<option value="">None</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="rvc_index_rate">
|
||||
Index rate for feature retrieval (<span id="rvc_index_rate_value"></span>)
|
||||
</label>
|
||||
@ -208,15 +255,17 @@ $(document).ready(function () {
|
||||
<label for="rvc_pitch_offset">Pitch offset (<span id="rvc_pitch_offset_value"></span>)</label>
|
||||
<input id="rvc_pitch_offset" type="range" min="-100" max="100" step="1" value="0" />
|
||||
|
||||
<label for="rvc_rms_mix_rate">Mix rate (<span id="rvc_rms_mix_rate_value"></span>)</label>
|
||||
<input id="rvc_rms_mix_rate" type="range" min="0" max="1" step="0.01" value="1" />
|
||||
|
||||
<label for="rvc_protect">Protect amount (<span id="rvc_protect_value"></span>)</label>
|
||||
<input id="rvc_protect" type="range" min="0" max="1" step="0.01" value="0.33" />
|
||||
<label>Voice Map</label>
|
||||
<textarea id="rvc_voice_map" type="text" class="text_pole textarea_compact" rows="4"
|
||||
placeholder="Enter comma separated map of charName:rvcModel. Example: \nAqua:Bella,\nYou:Josh,"></textarea>
|
||||
|
||||
<div id="rvc_status">
|
||||
</div>
|
||||
<div class="rvc_buttons">
|
||||
<input id="rvc_apply" class="menu_button" type="submit" value="Apply" />
|
||||
<input id="rvc_delete" class="menu_button" type="submit" value="Delete" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -225,14 +274,157 @@ $(document).ready(function () {
|
||||
`;
|
||||
$('#extensions_settings').append(settingsHtml);
|
||||
$("#rvc_enabled").on("click", onEnabledClick);
|
||||
$("#rvc_voice_map").attr("disabled", "disabled");;
|
||||
$('#rvc_pitch_extraction').on('change', onPitchExtractionChange);
|
||||
$('#rvc_index_rate').on('input', onIndexRateChange);
|
||||
$('#rvc_filter_radius').on('input', onFilterRadiusChange);
|
||||
$('#rvc_pitch_offset').on('input', onPitchOffsetChange);
|
||||
$('#rvc_rms_mix_rate').on('input', onRmsMixRateChange);
|
||||
$('#rvc_protect').on('input', onProtectChange);
|
||||
$("#rvc_apply").on("click", onApplyClick);
|
||||
|
||||
$("#rvc_delete").on("click", onDeleteClick);
|
||||
|
||||
$("#rvc_model_upload_file").show();
|
||||
$("#rvc_model_upload_button").on("click", onClickUpload);
|
||||
$("#rvc_model_refresh_button").on("click", refreshVoiceList);
|
||||
|
||||
}
|
||||
addExtensionControls(); // No init dependencies
|
||||
loadSettings(); // Depends on Extension Controls
|
||||
|
||||
const wrapper = new ModuleWorkerWrapper(moduleWorker);
|
||||
setInterval(wrapper.update.bind(wrapper), UPDATE_INTERVAL);
|
||||
moduleWorker();
|
||||
})
|
||||
|
||||
//#############################//
|
||||
// API Calls //
|
||||
//#############################//
|
||||
|
||||
/*
|
||||
Check model installation state, return one of ["installed", "corrupted", "absent"]
|
||||
*/
|
||||
async function get_models_list(model_id) {
|
||||
const url = new URL(getApiUrl());
|
||||
url.pathname = '/api/voice-conversion/rvc/get-models-list';
|
||||
|
||||
const apiResult = await doExtrasFetch(url, {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (!apiResult.ok) {
|
||||
toastr.error(apiResult.statusText, DEBUG_PREFIX + ' Check model state request failed');
|
||||
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`);
|
||||
}
|
||||
|
||||
return apiResult
|
||||
}
|
||||
|
||||
/*
|
||||
Send an audio file to RVC to convert voice
|
||||
*/
|
||||
async function rvcVoiceConversion(response, character) {
|
||||
let apiResult
|
||||
|
||||
// Check voice map
|
||||
if (extension_settings.rvc.voiceMap[character] === undefined) {
|
||||
//toastr.error("No model is assigned to character '"+character+"', check RVC voice map in the extension menu.", DEBUG_PREFIX+'RVC Voice map error', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
console.info(DEBUG_PREFIX, "No RVC model assign in voice map for current character " + character);
|
||||
return response;
|
||||
}
|
||||
|
||||
const audioData = await response.blob()
|
||||
if (!audioData.type in ['audio/mpeg', 'audio/wav', 'audio/x-wav', 'audio/wave', 'audio/webm']) {
|
||||
throw `TTS received HTTP response with invalid data format. Expecting audio/mpeg, got ${audioData.type}`
|
||||
}
|
||||
console.log("Audio type received:", audioData.type)
|
||||
|
||||
const voice_settings = extension_settings.rvc.voiceMap[character];
|
||||
|
||||
console.log("Sending tts audio data to RVC on extras server")
|
||||
|
||||
var requestData = new FormData();
|
||||
requestData.append('AudioFile', audioData, 'record');
|
||||
requestData.append("json", JSON.stringify({
|
||||
"modelName": voice_settings["modelName"],
|
||||
"pitchExtraction": voice_settings["pitchExtraction"],
|
||||
"pitchOffset": voice_settings["pitchOffset"],
|
||||
"indexRate": voice_settings["indexRate"],
|
||||
"filterRadius": voice_settings["filterRadius"],
|
||||
"rmsMixRate": voice_settings["rmsMixRate"],
|
||||
"protect": voice_settings["protect"]
|
||||
}));
|
||||
|
||||
const url = new URL(getApiUrl());
|
||||
url.pathname = '/api/voice-conversion/rvc/process-audio';
|
||||
|
||||
apiResult = await doExtrasFetch(url, {
|
||||
method: 'POST',
|
||||
body: requestData,
|
||||
});
|
||||
|
||||
if (!apiResult.ok) {
|
||||
toastr.error(apiResult.statusText, DEBUG_PREFIX + ' RVC Voice Conversion Failed', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`);
|
||||
}
|
||||
|
||||
return apiResult;
|
||||
}
|
||||
|
||||
//#############################//
|
||||
// Module Worker //
|
||||
//#############################//
|
||||
|
||||
async function refreshVoiceList() {
|
||||
let result = await get_models_list();
|
||||
result = await result.json();
|
||||
rvcModelsList = result["models_list"]
|
||||
|
||||
$('#rvc_model_select')
|
||||
.find('option')
|
||||
.remove()
|
||||
.end()
|
||||
.append('<option value="none">Select Voice</option>')
|
||||
.val('none')
|
||||
|
||||
for (const modelName of rvcModelsList) {
|
||||
$("#rvc_model_select").append(new Option(modelName, modelName));
|
||||
}
|
||||
|
||||
rvcModelsReceived = true
|
||||
console.debug(DEBUG_PREFIX, "Updated model list to:", rvcModelsList);
|
||||
}
|
||||
|
||||
async function moduleWorker() {
|
||||
updateCharactersList();
|
||||
|
||||
if (modules.includes('rvc') && !rvcModelsReceived) {
|
||||
refreshVoiceList();
|
||||
}
|
||||
}
|
||||
|
||||
function updateCharactersList() {
|
||||
let currentcharacters = new Set();
|
||||
for (const i of getContext().characters) {
|
||||
currentcharacters.add(i.name);
|
||||
}
|
||||
|
||||
currentcharacters = Array.from(currentcharacters)
|
||||
|
||||
if (JSON.stringify(charactersList) !== JSON.stringify(currentcharacters)) {
|
||||
charactersList = currentcharacters
|
||||
|
||||
$('#rvc_character_select')
|
||||
.find('option')
|
||||
.remove()
|
||||
.end()
|
||||
.append('<option value="none">Select Character</option>')
|
||||
.val('none')
|
||||
|
||||
for (const charName of charactersList) {
|
||||
$("#rvc_character_select").append(new Option(charName, charName));
|
||||
}
|
||||
|
||||
console.debug(DEBUG_PREFIX, "Updated character list to:", charactersList);
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ const generationMode = {
|
||||
NOW: 4,
|
||||
FACE: 5,
|
||||
FREE: 6,
|
||||
BACKGROUND: 7,
|
||||
}
|
||||
|
||||
const modeLabels = {
|
||||
@ -49,6 +50,7 @@ const modeLabels = {
|
||||
[generationMode.SCENARIO]: 'Scenario ("The Whole Story")',
|
||||
[generationMode.NOW]: 'Last Message',
|
||||
[generationMode.RAW_LAST]: 'Raw Last Message',
|
||||
[generationMode.BACKGROUND]: 'Background',
|
||||
}
|
||||
|
||||
const triggerWords = {
|
||||
@ -58,6 +60,7 @@ const triggerWords = {
|
||||
[generationMode.RAW_LAST]: ['raw_last'],
|
||||
[generationMode.NOW]: ['last'],
|
||||
[generationMode.FACE]: ['face'],
|
||||
[generationMode.BACKGROUND]: ['background'],
|
||||
}
|
||||
|
||||
const promptTemplates = {
|
||||
@ -94,6 +97,7 @@ const promptTemplates = {
|
||||
'(location),(character list by gender),(primary action), (relative character position) POV, (character 1's description and actions), (character 2's description and actions)']`,
|
||||
|
||||
[generationMode.RAW_LAST]: "[Pause your roleplay and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not roleplay at all in your response. Do not continue the roleplay story.]",
|
||||
[generationMode.BACKGROUND]: "[Pause your roleplay and provide a detailed description of {{char}}'s surroundings in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: location, time of day, weather, lighting, and any other relevant details. Do not include descriptions of characters and non-visual qualities such as names, personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'background,'. Ignore the rest of the story when crafting this description. Do not roleplay as {{user}} when writing this description, and do not attempt to continue the story.]",
|
||||
}
|
||||
|
||||
const helpString = [
|
||||
@ -105,6 +109,7 @@ const helpString = [
|
||||
`<li>${m(j(triggerWords[generationMode.SCENARIO]))} – visual recap of the whole chat scenario</li>`,
|
||||
`<li>${m(j(triggerWords[generationMode.NOW]))} – visual recap of the last chat message</li>`,
|
||||
`<li>${m(j(triggerWords[generationMode.RAW_LAST]))} – visual recap of the last chat message with no summary</li>`,
|
||||
`<li>${m(j(triggerWords[generationMode.BACKGROUND]))} – generate a background for this chat based on the chat's context</li>`,
|
||||
'</ul>',
|
||||
`Anything else would trigger a "free mode" to make SD generate whatever you prompted.<Br>
|
||||
example: '/sd apple tree' would generate a picture of an apple tree.`,
|
||||
@ -159,6 +164,13 @@ async function loadSettings() {
|
||||
extension_settings.sd.prompts = promptTemplates;
|
||||
}
|
||||
|
||||
// Insert missing templates
|
||||
for (const [key, value] of Object.entries(promptTemplates)) {
|
||||
if (extension_settings.sd.prompts[key] === undefined) {
|
||||
extension_settings.sd.prompts[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (extension_settings.sd.character_prompts === undefined) {
|
||||
extension_settings.sd.character_prompts = {};
|
||||
}
|
||||
@ -554,9 +566,35 @@ async function generatePicture(_, trigger, message, callback) {
|
||||
const context = getContext();
|
||||
|
||||
const prevSDHeight = extension_settings.sd.height;
|
||||
if (generationType == generationMode.FACE) {
|
||||
const prevSDWidth = extension_settings.sd.width;
|
||||
const aspectRatio = extension_settings.sd.width / extension_settings.sd.height;
|
||||
|
||||
// Face images are always portrait (pun intended)
|
||||
if (generationType == generationMode.FACE && aspectRatio >= 1) {
|
||||
// Round to nearest multiple of 64
|
||||
extension_settings.sd.height = Math.round(extension_settings.sd.height * 1.5 / 64) * 64;
|
||||
extension_settings.sd.height = Math.round(extension_settings.sd.width * 1.5 / 64) * 64;
|
||||
}
|
||||
|
||||
// Background images are always landscape
|
||||
if (generationType == generationMode.BACKGROUND && aspectRatio <= 1) {
|
||||
// Round to nearest multiple of 64
|
||||
extension_settings.sd.width = Math.round(extension_settings.sd.height * 1.8 / 64) * 64;
|
||||
const callbackOriginal = callback;
|
||||
callback = function (prompt, base64Image) {
|
||||
const imgUrl = `url(${base64Image})`;
|
||||
if ('forceSetBackground' in window) {
|
||||
forceSetBackground(imgUrl);
|
||||
} else {
|
||||
toastr.info('Background image will not be preserved.', '"Chat backgrounds" extension is disabled.');
|
||||
$('#bg_custom').css('background-image', imgUrl);
|
||||
}
|
||||
|
||||
if (typeof callbackOriginal === 'function') {
|
||||
callbackOriginal(prompt, base64Image);
|
||||
} else {
|
||||
sendMessage(prompt, base64Image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@ -566,13 +604,14 @@ async function generatePicture(_, trigger, message, callback) {
|
||||
context.deactivateSendButtons();
|
||||
hideSwipeButtons();
|
||||
|
||||
await sendGenerationRequest(prompt, callback);
|
||||
await sendGenerationRequest(generationType, prompt, callback);
|
||||
} catch (err) {
|
||||
console.trace(err);
|
||||
throw new Error('SD prompt text generation failed.')
|
||||
}
|
||||
finally {
|
||||
extension_settings.sd.height = prevSDHeight;
|
||||
extension_settings.sd.width = prevSDWidth;
|
||||
context.activateSendButtons();
|
||||
showSwipeButtons();
|
||||
}
|
||||
@ -605,16 +644,20 @@ async function generatePrompt(quiet_prompt) {
|
||||
return processReply(reply);
|
||||
}
|
||||
|
||||
async function sendGenerationRequest(prompt, callback) {
|
||||
async function sendGenerationRequest(generationType, prompt, callback) {
|
||||
const prefix = generationType !== generationMode.BACKGROUND
|
||||
? combinePrefixes(extension_settings.sd.prompt_prefix, getCharacterPrefix())
|
||||
: extension_settings.sd.prompt_prefix;
|
||||
|
||||
if (extension_settings.sd.horde) {
|
||||
await generateHordeImage(prompt, callback);
|
||||
await generateHordeImage(prompt, prefix, callback);
|
||||
} else {
|
||||
await generateExtrasImage(prompt, callback);
|
||||
await generateExtrasImage(prompt, prefix, callback);
|
||||
}
|
||||
}
|
||||
|
||||
async function generateExtrasImage(prompt, callback) {
|
||||
console.log(extension_settings.sd);
|
||||
async function generateExtrasImage(prompt, prefix, callback) {
|
||||
console.debug(extension_settings.sd);
|
||||
const url = new URL(getApiUrl());
|
||||
url.pathname = '/api/image';
|
||||
const result = await doExtrasFetch(url, {
|
||||
@ -627,7 +670,7 @@ async function generateExtrasImage(prompt, callback) {
|
||||
scale: extension_settings.sd.scale,
|
||||
width: extension_settings.sd.width,
|
||||
height: extension_settings.sd.height,
|
||||
prompt_prefix: combinePrefixes(extension_settings.sd.prompt_prefix, getCharacterPrefix()),
|
||||
prompt_prefix: prefix,
|
||||
negative_prompt: extension_settings.sd.negative_prompt,
|
||||
restore_faces: !!extension_settings.sd.restore_faces,
|
||||
enable_hr: !!extension_settings.sd.enable_hr,
|
||||
@ -644,7 +687,7 @@ async function generateExtrasImage(prompt, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
async function generateHordeImage(prompt, callback) {
|
||||
async function generateHordeImage(prompt, prefix, callback) {
|
||||
const result = await fetch('/horde_generateimage', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
@ -655,7 +698,7 @@ async function generateHordeImage(prompt, callback) {
|
||||
scale: extension_settings.sd.scale,
|
||||
width: extension_settings.sd.width,
|
||||
height: extension_settings.sd.height,
|
||||
prompt_prefix: combinePrefixes(extension_settings.sd.prompt_prefix, getCharacterPrefix()),
|
||||
prompt_prefix: prefix,
|
||||
negative_prompt: extension_settings.sd.negative_prompt,
|
||||
model: extension_settings.sd.model,
|
||||
nsfw: extension_settings.sd.horde_nsfw,
|
||||
@ -680,6 +723,7 @@ async function sendMessage(prompt, image) {
|
||||
name: context.groupId ? systemUserName : context.name2,
|
||||
is_system: context.groupId ? true : false,
|
||||
is_user: false,
|
||||
is_system: true,
|
||||
is_name: true,
|
||||
send_date: timestampToMoment(Date.now()).format('LL LT'),
|
||||
mes: context.groupId ? p(messageText) : messageText,
|
||||
@ -715,6 +759,7 @@ function addSDGenButtons() {
|
||||
<li class="list-group-item" id="sd_world" data-value="world">The Whole Story</li>
|
||||
<li class="list-group-item" id="sd_last" data-value="last">The Last Message</li>
|
||||
<li class="list-group-item" id="sd_raw_last" data-value="raw_last">Raw Last Message</li>
|
||||
<li class="list-group-item" id="sd_background" data-value="background">Background</li>
|
||||
</ul>
|
||||
</div>`;
|
||||
|
||||
@ -797,7 +842,7 @@ async function sdMessageButton(e) {
|
||||
message.extra.title = prompt;
|
||||
|
||||
console.log('Regenerating an image, using existing prompt:', prompt);
|
||||
await sendGenerationRequest(prompt, saveGeneratedImage);
|
||||
await sendGenerationRequest(generationMode.FREE, prompt, saveGeneratedImage);
|
||||
}
|
||||
else {
|
||||
console.log("doing /sd raw last");
|
||||
@ -828,36 +873,22 @@ async function sdMessageButton(e) {
|
||||
};
|
||||
|
||||
$("#sd_dropdown [id]").on("click", function () {
|
||||
var id = $(this).attr("id");
|
||||
if (id == "sd_you") {
|
||||
console.log("doing /sd you");
|
||||
generatePicture('sd', 'you');
|
||||
}
|
||||
const id = $(this).attr("id");
|
||||
const idParamMap = {
|
||||
"sd_you": "you",
|
||||
"sd_face": "face",
|
||||
"sd_me": "me",
|
||||
"sd_world": "scene",
|
||||
"sd_last": "last",
|
||||
"sd_raw_last": "raw_last",
|
||||
"sd_background": "background"
|
||||
};
|
||||
|
||||
else if (id == "sd_face") {
|
||||
console.log("doing /sd face");
|
||||
generatePicture('sd', 'face');
|
||||
const param = idParamMap[id];
|
||||
|
||||
}
|
||||
|
||||
else if (id == "sd_me") {
|
||||
console.log("doing /sd me");
|
||||
generatePicture('sd', 'me');
|
||||
}
|
||||
|
||||
else if (id == "sd_world") {
|
||||
console.log("doing /sd scene");
|
||||
generatePicture('sd', 'scene');
|
||||
}
|
||||
|
||||
else if (id == "sd_last") {
|
||||
console.log("doing /sd last");
|
||||
generatePicture('sd', 'last');
|
||||
}
|
||||
|
||||
else if (id == "sd_raw_last") {
|
||||
console.log("doing /sd raw last");
|
||||
generatePicture('sd', 'raw_last');
|
||||
if (param) {
|
||||
console.log("doing /sd " + param)
|
||||
generatePicture('sd', param);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -4,17 +4,19 @@ TODO:
|
||||
- Delete useless call
|
||||
*/
|
||||
|
||||
import { saveSettingsDebounced } from "../../../script.js"
|
||||
import { doExtrasFetch, extension_settings, getApiUrl, getContext, modules, ModuleWorkerWrapper } from "../../extensions.js"
|
||||
|
||||
export { CoquiTtsProvider }
|
||||
|
||||
const DEBUG_PREFIX = "<Coqui TTS module> "
|
||||
const UPDATE_INTERVAL = 1000
|
||||
const DEBUG_PREFIX = "<Coqui TTS module> ";
|
||||
const UPDATE_INTERVAL = 1000;
|
||||
|
||||
let inApiCall = false
|
||||
let charactersList = [] // Updated with module worker
|
||||
let coquiApiModels = {} // Initialized only once
|
||||
let inApiCall = false;
|
||||
let charactersList = []; // Updated with module worker
|
||||
let coquiApiModels = {}; // Initialized only once
|
||||
let coquiApiModelsFull = {}; // Initialized only once
|
||||
let coquiLocalModels = []; // Initialized only once
|
||||
let coquiLocalModelsReceived = false;
|
||||
/*
|
||||
coquiApiModels format [language][dataset][name]:coqui-api-model-id, example:
|
||||
{
|
||||
@ -32,24 +34,19 @@ coquiApiModels format [language][dataset][name]:coqui-api-model-id, example:
|
||||
*/
|
||||
const languageLabels = {
|
||||
"multilingual": "Multilingual",
|
||||
"en" : "English",
|
||||
"fr" : "French",
|
||||
"es" : "Spanish",
|
||||
"ja" : "Japanese"
|
||||
"en": "English",
|
||||
"fr": "French",
|
||||
"es": "Spanish",
|
||||
"ja": "Japanese"
|
||||
}
|
||||
|
||||
function throwIfModuleMissing() {
|
||||
if (!modules.includes('coqui-tts')) {
|
||||
toastr.error(`Add coqui-tts to enable-modules and restart the Extras API.`, "Coqui TTS module not loaded.", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
throw new Error(DEBUG_PREFIX,`Coqui TTS module not loaded.`);
|
||||
throw new Error(DEBUG_PREFIX, `Coqui TTS module not loaded.`);
|
||||
}
|
||||
}
|
||||
|
||||
function throwLocalOrigin() {
|
||||
toastr.info("coming soon, ready when ready, etc", DEBUG_PREFIX+' Custom models not supported yet', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
throw new Error(DEBUG_PREFIX,`requesting feature not implemented yet.`);
|
||||
}
|
||||
|
||||
function resetModelSettings() {
|
||||
$("#coqui_api_model_settings_language").val("none");
|
||||
$("#coqui_api_model_settings_speaker").val("none");
|
||||
@ -62,7 +59,7 @@ function updateCharactersList() {
|
||||
}
|
||||
|
||||
currentcharacters = Array.from(currentcharacters)
|
||||
|
||||
|
||||
if (JSON.stringify(charactersList) !== JSON.stringify(currentcharacters)) {
|
||||
charactersList = currentcharacters
|
||||
|
||||
@ -72,12 +69,12 @@ function updateCharactersList() {
|
||||
.end()
|
||||
.append('<option value="none">Select Character</option>')
|
||||
.val('none')
|
||||
|
||||
for(const charName of charactersList) {
|
||||
$("#coqui_character_select").append(new Option(charName,charName));
|
||||
|
||||
for (const charName of charactersList) {
|
||||
$("#coqui_character_select").append(new Option(charName, charName));
|
||||
}
|
||||
|
||||
console.debug(DEBUG_PREFIX,"Updated character list to:", charactersList);
|
||||
console.debug(DEBUG_PREFIX, "Updated character list to:", charactersList);
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +87,7 @@ class CoquiTtsProvider {
|
||||
|
||||
defaultSettings = {
|
||||
voiceMap: "",
|
||||
voiceMapDict : {}
|
||||
voiceMapDict: {}
|
||||
}
|
||||
|
||||
get settingsHtml() {
|
||||
@ -102,11 +99,15 @@ class CoquiTtsProvider {
|
||||
<select id="coqui_character_select">
|
||||
<!-- Populated by JS -->
|
||||
</select>
|
||||
|
||||
<input id="coqui_remove_char_mapping" class="menu_button" type="button" value="Remove from Voice Map" />
|
||||
|
||||
<label for="coqui_model_origin">Models:</label>
|
||||
<select id="coqui_model_origin">gpu_mode
|
||||
<option value="none">Select Origin</option>
|
||||
<option value="coqui-api">Coqui TTS</option>
|
||||
<option value="local">My models</option>
|
||||
<option value="coqui-api">Coqui API (Tested)</option>
|
||||
<option value="coqui-api-full">Coqui API (Experimental)</option>
|
||||
<option value="local">My Models</option>
|
||||
</select>
|
||||
|
||||
<div id="coqui_api_model_div">
|
||||
@ -129,6 +130,13 @@ class CoquiTtsProvider {
|
||||
<span id="coqui_api_model_install_status">Model installed on extras server</span>
|
||||
<input id="coqui_api_model_install_button" class="menu_button" type="button" value="Install" />
|
||||
</div>
|
||||
|
||||
<div id="coqui_local_model_div">
|
||||
<select id="coqui_local_model_name">
|
||||
<!-- Populated by JS and request -->
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -140,25 +148,31 @@ class CoquiTtsProvider {
|
||||
// Only accept keys defined in defaultSettings
|
||||
this.settings = this.defaultSettings
|
||||
|
||||
for (const key in settings){
|
||||
if (key in this.settings){
|
||||
for (const key in settings) {
|
||||
if (key in this.settings) {
|
||||
this.settings[key] = settings[key]
|
||||
} else {
|
||||
throw DEBUG_PREFIX+`Invalid setting passed to extension: ${key}`
|
||||
throw DEBUG_PREFIX + `Invalid setting passed to extension: ${key}`
|
||||
}
|
||||
}
|
||||
|
||||
this.updateVoiceMap(); // Overide any manual modification
|
||||
|
||||
$("#coqui_api_model_div").hide();
|
||||
$("#coqui_local_model_div").hide();
|
||||
|
||||
$("#coqui_api_language").show();
|
||||
$("#coqui_api_model_name").hide();
|
||||
$("#coqui_api_model_settings").hide();
|
||||
$("#coqui_api_model_install_status").hide();
|
||||
$("#coqui_api_model_install_button").hide();
|
||||
|
||||
$("#coqui_model_origin").on("change",this.onModelOriginChange);
|
||||
$("#coqui_api_language").on("change",this.onModelLanguageChange);
|
||||
$("#coqui_api_model_name").on("change",this.onModelNameChange);
|
||||
let that = this
|
||||
$("#coqui_model_origin").on("change", function () { that.onModelOriginChange() });
|
||||
$("#coqui_api_language").on("change", function () { that.onModelLanguageChange() });
|
||||
$("#coqui_api_model_name").on("change", function () { that.onModelNameChange() });
|
||||
|
||||
$("#coqui_remove_char_mapping").on("click", function () { that.onRemoveClick() });
|
||||
|
||||
// Load characters list
|
||||
$('#coqui_character_select')
|
||||
@ -167,9 +181,9 @@ class CoquiTtsProvider {
|
||||
.end()
|
||||
.append('<option value="none">Select Character</option>')
|
||||
.val('none')
|
||||
|
||||
for(const charName of charactersList) {
|
||||
$("#coqui_character_select").append(new Option(charName,charName));
|
||||
|
||||
for (const charName of charactersList) {
|
||||
$("#coqui_character_select").append(new Option(charName, charName));
|
||||
}
|
||||
|
||||
// Load coqui-api settings from json file
|
||||
@ -178,7 +192,7 @@ class CoquiTtsProvider {
|
||||
.then(json => {
|
||||
coquiApiModels = json;
|
||||
console.debug(DEBUG_PREFIX,"initialized coqui-api model list to", coquiApiModels);
|
||||
|
||||
/*
|
||||
$('#coqui_api_language')
|
||||
.find('option')
|
||||
.remove()
|
||||
@ -189,13 +203,33 @@ class CoquiTtsProvider {
|
||||
for(let language in coquiApiModels) {
|
||||
$("#coqui_api_language").append(new Option(languageLabels[language],language));
|
||||
console.log(DEBUG_PREFIX,"added language",language);
|
||||
}
|
||||
}*/
|
||||
});
|
||||
|
||||
// Load coqui-api FULL settings from json file
|
||||
fetch("/scripts/extensions/tts/coqui_api_models_settings_full.json")
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
coquiApiModelsFull = json;
|
||||
console.debug(DEBUG_PREFIX,"initialized coqui-api full model list to", coquiApiModelsFull);
|
||||
/*
|
||||
$('#coqui_api_full_language')
|
||||
.find('option')
|
||||
.remove()
|
||||
.end()
|
||||
.append('<option value="none">Select model language</option>')
|
||||
.val('none');
|
||||
|
||||
for(let language in coquiApiModelsFull) {
|
||||
$("#coqui_api_full_language").append(new Option(languageLabels[language],language));
|
||||
console.log(DEBUG_PREFIX,"added language",language);
|
||||
}*/
|
||||
});
|
||||
}
|
||||
|
||||
updateVoiceMap(){
|
||||
updateVoiceMap() {
|
||||
this.settings.voiceMap = "";
|
||||
for(let i in this.settings.voiceMapDict) {
|
||||
for (let i in this.settings.voiceMapDict) {
|
||||
const voice_settings = this.settings.voiceMapDict[i];
|
||||
this.settings.voiceMap += i + ":" + voice_settings["model_id"];
|
||||
|
||||
@ -210,9 +244,9 @@ class CoquiTtsProvider {
|
||||
$("#tts_voice_map").val(this.settings.voiceMap);
|
||||
extension_settings.tts.Coqui = this.settings;
|
||||
}
|
||||
|
||||
|
||||
onSettingsChange() {
|
||||
console.debug(DEBUG_PREFIX,"Settings changes",this.settings);
|
||||
console.debug(DEBUG_PREFIX, "Settings changes", this.settings);
|
||||
extension_settings.tts.Coqui = this.settings;
|
||||
}
|
||||
|
||||
@ -228,99 +262,168 @@ class CoquiTtsProvider {
|
||||
let model_setting_language = $("#coqui_api_model_settings_language").val();
|
||||
let model_setting_speaker = $("#coqui_api_model_settings_speaker").val();
|
||||
|
||||
|
||||
|
||||
if (character === "none") {
|
||||
toastr.error(`Character not selected, please select one.`, DEBUG_PREFIX+" voice mapping character", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
toastr.error(`Character not selected, please select one.`, DEBUG_PREFIX + " voice mapping character", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
this.updateVoiceMap(); // Overide any manual modification
|
||||
return;
|
||||
}
|
||||
|
||||
if (model_origin == "none") {
|
||||
toastr.error(`Origin not selected, please select one.`, DEBUG_PREFIX+" voice mapping origin", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
toastr.error(`Origin not selected, please select one.`, DEBUG_PREFIX + " voice mapping origin", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
this.updateVoiceMap(); // Overide any manual modification
|
||||
return;
|
||||
}
|
||||
|
||||
if (model_origin == "local") {
|
||||
throwLocalOrigin();
|
||||
const model_id = $("#coqui_local_model_name").val();
|
||||
|
||||
if (model_name == "none") {
|
||||
toastr.error(`Model not selected, please select one.`, DEBUG_PREFIX + " voice mapping model", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
this.updateVoiceMap(); // Overide any manual modification
|
||||
return;
|
||||
}
|
||||
|
||||
this.settings.voiceMapDict[character] = { model_type: "local", model_id: "local/" + model_id };
|
||||
console.debug(DEBUG_PREFIX, "Registered new voice map: ", character, ":", this.settings.voiceMapDict[character]);
|
||||
this.updateVoiceMap(); // Overide any manual modification
|
||||
return;
|
||||
}
|
||||
|
||||
if (model_language == "none") {
|
||||
toastr.error(`Language not selected, please select one.`, DEBUG_PREFIX+" voice mapping language", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
toastr.error(`Language not selected, please select one.`, DEBUG_PREFIX + " voice mapping language", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
this.updateVoiceMap(); // Overide any manual modification
|
||||
return;
|
||||
}
|
||||
|
||||
if (model_name == "none") {
|
||||
toastr.error(`Model not selected, please select one.`, DEBUG_PREFIX+" voice mapping model", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
toastr.error(`Model not selected, please select one.`, DEBUG_PREFIX + " voice mapping model", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
this.updateVoiceMap(); // Overide any manual modification
|
||||
return;
|
||||
}
|
||||
|
||||
if (model_setting_language == "none")
|
||||
model_setting_language = null;
|
||||
|
||||
|
||||
if (model_setting_speaker == "none")
|
||||
model_setting_speaker = null;
|
||||
|
||||
|
||||
const tokens = $('#coqui_api_model_name').val().split("/");
|
||||
const model_dataset = tokens[0];
|
||||
const model_label = tokens[1];
|
||||
const model_id = "tts_models/" + model_language + "/" + model_dataset + "/" + model_label
|
||||
|
||||
if (model_setting_language == null & "languages" in coquiApiModels[model_language][model_dataset][model_label]) {
|
||||
let modelDict = coquiApiModels
|
||||
if (model_origin == "coqui-api-full")
|
||||
modelDict = coquiApiModelsFull
|
||||
|
||||
if (model_setting_language == null & "languages" in modelDict[model_language][model_dataset][model_label]) {
|
||||
toastr.error(`Model language not selected, please select one.`, DEBUG_PREFIX+" voice mapping model language", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (model_setting_speaker == null & "speakers" in coquiApiModels[model_language][model_dataset][model_label]) {
|
||||
if (model_setting_speaker == null & "speakers" in modelDict[model_language][model_dataset][model_label]) {
|
||||
toastr.error(`Model speaker not selected, please select one.`, DEBUG_PREFIX+" voice mapping model speaker", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug(DEBUG_PREFIX,"Current voice map: ",this.settings.voiceMap);
|
||||
console.debug(DEBUG_PREFIX, "Current voice map: ", this.settings.voiceMap);
|
||||
|
||||
this.settings.voiceMapDict[character] = {model_id: model_id, model_language:model_setting_language, model_speaker:model_setting_speaker};
|
||||
this.settings.voiceMapDict[character] = { model_type: "coqui-api", model_id: model_id, model_language: model_setting_language, model_speaker: model_setting_speaker };
|
||||
|
||||
console.debug(DEBUG_PREFIX,"Registered new voice map: ",character,":",this.settings.voiceMapDict[character]);
|
||||
console.debug(DEBUG_PREFIX, "Registered new voice map: ", character, ":", this.settings.voiceMapDict[character]);
|
||||
|
||||
this.updateVoiceMap();
|
||||
|
||||
let successMsg = character+":"+model_id;
|
||||
let successMsg = character + ":" + model_id;
|
||||
if (model_setting_language != null)
|
||||
successMsg += "[" + model_setting_language + "]";
|
||||
if (model_setting_speaker != null)
|
||||
successMsg += "[" + model_setting_speaker + "]";
|
||||
toastr.info(successMsg, DEBUG_PREFIX+" voice map updated", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
toastr.info(successMsg, DEBUG_PREFIX + " voice map updated", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
return
|
||||
}
|
||||
|
||||
// DBG: assume voiceName is correct
|
||||
// TODO: check voice is correct
|
||||
async getVoice(voiceName) {
|
||||
console.log(DEBUG_PREFIX,"getVoice",voiceName);
|
||||
const output = {voice_id: voiceName};
|
||||
console.log(DEBUG_PREFIX, "getVoice", voiceName);
|
||||
const output = { voice_id: voiceName };
|
||||
return output;
|
||||
}
|
||||
|
||||
async onRemoveClick() {
|
||||
const character = $("#coqui_character_select").val();
|
||||
|
||||
if (character === "none") {
|
||||
toastr.error(`Character not selected, please select one.`, DEBUG_PREFIX + " voice mapping character", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
return;
|
||||
}
|
||||
|
||||
// Todo erase from voicemap
|
||||
delete (this.settings.voiceMapDict[character]);
|
||||
this.updateVoiceMap(); // TODO
|
||||
}
|
||||
|
||||
async onModelOriginChange() {
|
||||
throwIfModuleMissing()
|
||||
resetModelSettings();
|
||||
const model_origin = $('#coqui_model_origin').val();
|
||||
console.debug(model_origin);
|
||||
|
||||
if (model_origin == "none") {
|
||||
$("#coqui_local_model_div").hide();
|
||||
$("#coqui_api_model_div").hide();
|
||||
}
|
||||
|
||||
// TODO: show coqui model list
|
||||
// show coqui model selected list (SAFE)
|
||||
if (model_origin == "coqui-api") {
|
||||
$("#coqui_local_model_div").hide();
|
||||
|
||||
$('#coqui_api_language')
|
||||
.find('option')
|
||||
.remove()
|
||||
.end()
|
||||
.append('<option value="none">Select model language</option>')
|
||||
.val('none');
|
||||
|
||||
for(let language in coquiApiModels) {
|
||||
let languageLabel = language
|
||||
if (language in languageLabels)
|
||||
languageLabel = languageLabels[language]
|
||||
$("#coqui_api_language").append(new Option(languageLabel,language));
|
||||
console.log(DEBUG_PREFIX,"added language",languageLabel,"(",language,")");
|
||||
}
|
||||
|
||||
$("#coqui_api_model_div").show();
|
||||
}
|
||||
else
|
||||
$("#coqui_api_model_div").hide();
|
||||
|
||||
// TODO show local model list
|
||||
// show coqui model full list (UNSAFE)
|
||||
if (model_origin == "coqui-api-full") {
|
||||
$("#coqui_local_model_div").hide();
|
||||
|
||||
$('#coqui_api_language')
|
||||
.find('option')
|
||||
.remove()
|
||||
.end()
|
||||
.append('<option value="none">Select model language</option>')
|
||||
.val('none');
|
||||
|
||||
for(let language in coquiApiModelsFull) {
|
||||
let languageLabel = language
|
||||
if (language in languageLabels)
|
||||
languageLabel = languageLabels[language]
|
||||
$("#coqui_api_language").append(new Option(languageLabel,language));
|
||||
console.log(DEBUG_PREFIX,"added language",languageLabel,"(",language,")");
|
||||
}
|
||||
|
||||
$("#coqui_api_model_div").show();
|
||||
}
|
||||
|
||||
|
||||
// show local model list
|
||||
if (model_origin == "local") {
|
||||
throwLocalOrigin();
|
||||
$("#coqui_api_model_div").hide();
|
||||
$("#coqui_local_model_div").show();
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,12 +434,12 @@ class CoquiTtsProvider {
|
||||
const model_origin = $('#coqui_model_origin').val();
|
||||
const model_language = $('#coqui_api_language').val();
|
||||
console.debug(model_language);
|
||||
|
||||
|
||||
if (model_language == "none") {
|
||||
$("#coqui_api_model_name").hide();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$("#coqui_api_model_name").show();
|
||||
$('#coqui_api_model_name')
|
||||
.find('option')
|
||||
@ -345,18 +448,23 @@ class CoquiTtsProvider {
|
||||
.append('<option value="none">Select model</option>')
|
||||
.val('none');
|
||||
|
||||
for(let model_dataset in coquiApiModels[model_language])
|
||||
for(let model_name in coquiApiModels[model_language][model_dataset]) {
|
||||
let modelDict = coquiApiModels
|
||||
if (model_origin == "coqui-api-full")
|
||||
modelDict = coquiApiModelsFull
|
||||
|
||||
for(let model_dataset in modelDict[model_language])
|
||||
for(let model_name in modelDict[model_language][model_dataset]) {
|
||||
const model_id = model_dataset + "/" + model_name
|
||||
const model_label = model_name + " ("+model_dataset+" dataset)"
|
||||
$("#coqui_api_model_name").append(new Option(model_label,model_id));
|
||||
}
|
||||
const model_label = model_name + " (" + model_dataset + " dataset)"
|
||||
$("#coqui_api_model_name").append(new Option(model_label, model_id));
|
||||
}
|
||||
}
|
||||
|
||||
async onModelNameChange() {
|
||||
throwIfModuleMissing();
|
||||
resetModelSettings();
|
||||
$("#coqui_api_model_settings").hide();
|
||||
const model_origin = $('#coqui_model_origin').val();
|
||||
|
||||
// No model selected
|
||||
if ($('#coqui_api_model_name').val() == "none") {
|
||||
@ -371,21 +479,25 @@ class CoquiTtsProvider {
|
||||
const model_dataset = tokens[0];
|
||||
const model_name = tokens[1];
|
||||
|
||||
const model_settings = coquiApiModels[model_language][model_dataset][model_name]
|
||||
let modelDict = coquiApiModels
|
||||
if (model_origin == "coqui-api-full")
|
||||
modelDict = coquiApiModelsFull
|
||||
|
||||
const model_settings = modelDict[model_language][model_dataset][model_name]
|
||||
|
||||
if ("languages" in model_settings) {
|
||||
$("#coqui_api_model_settings").show();
|
||||
$("#coqui_api_model_settings_language").show();
|
||||
$('#coqui_api_model_settings_language')
|
||||
.find('option')
|
||||
.remove()
|
||||
.end()
|
||||
.append('<option value="none">Select language</option>')
|
||||
.val('none');
|
||||
.find('option')
|
||||
.remove()
|
||||
.end()
|
||||
.append('<option value="none">Select language</option>')
|
||||
.val('none');
|
||||
|
||||
for(var i = 0; i < model_settings["languages"].length; i++) {
|
||||
const language_label = JSON.stringify(model_settings["languages"][i]).replaceAll("\"","");
|
||||
$("#coqui_api_model_settings_language").append(new Option(language_label,i));
|
||||
for (var i = 0; i < model_settings["languages"].length; i++) {
|
||||
const language_label = JSON.stringify(model_settings["languages"][i]).replaceAll("\"", "");
|
||||
$("#coqui_api_model_settings_language").append(new Option(language_label, i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -396,15 +508,15 @@ class CoquiTtsProvider {
|
||||
$("#coqui_api_model_settings").show();
|
||||
$("#coqui_api_model_settings_speaker").show();
|
||||
$('#coqui_api_model_settings_speaker')
|
||||
.find('option')
|
||||
.remove()
|
||||
.end()
|
||||
.append('<option value="none">Select speaker</option>')
|
||||
.val('none');
|
||||
.find('option')
|
||||
.remove()
|
||||
.end()
|
||||
.append('<option value="none">Select speaker</option>')
|
||||
.val('none');
|
||||
|
||||
for(var i = 0; i < model_settings["speakers"].length;i++) {
|
||||
const speaker_label = JSON.stringify(model_settings["speakers"][i]).replaceAll("\"","");
|
||||
$("#coqui_api_model_settings_speaker").append(new Option(speaker_label,i));
|
||||
for (var i = 0; i < model_settings["speakers"].length; i++) {
|
||||
const speaker_label = JSON.stringify(model_settings["speakers"][i]).replaceAll("\"", "");
|
||||
$("#coqui_api_model_settings_speaker").append(new Option(speaker_label, i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -415,13 +527,13 @@ class CoquiTtsProvider {
|
||||
$("#coqui_api_model_install_status").show();
|
||||
|
||||
// Check if already installed and propose to do it otherwise
|
||||
const model_id = coquiApiModels[model_language][model_dataset][model_name]["id"]
|
||||
const model_id = modelDict[model_language][model_dataset][model_name]["id"]
|
||||
console.debug(DEBUG_PREFIX,"Check if model is already installed",model_id);
|
||||
let result = await CoquiTtsProvider.checkmodel_state(model_id);
|
||||
result = await result.json();
|
||||
const model_state = result["model_state"];
|
||||
|
||||
console.debug(DEBUG_PREFIX," Model state:", model_state)
|
||||
console.debug(DEBUG_PREFIX, " Model state:", model_state)
|
||||
|
||||
if (model_state == "installed") {
|
||||
$("#coqui_api_model_install_status").text("Model already installed on extras server");
|
||||
@ -435,13 +547,13 @@ class CoquiTtsProvider {
|
||||
$("#coqui_api_model_install_status").text("Model found but incomplete try install again (maybe still downloading)"); // (remove and download again)
|
||||
}
|
||||
else {
|
||||
toastr.info("Click download button to install the model "+$("#coqui_api_model_name").find(":selected").text(), DEBUG_PREFIX+" model not installed", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
toastr.info("Click download button to install the model " + $("#coqui_api_model_name").find(":selected").text(), DEBUG_PREFIX + " model not installed", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
$("#coqui_api_model_install_status").text("Model not found on extras server");
|
||||
}
|
||||
|
||||
const onModelNameChange_pointer = this.onModelNameChange;
|
||||
|
||||
$("#coqui_api_model_install_button").off("click").on("click", async function (){
|
||||
$("#coqui_api_model_install_button").off("click").on("click", async function () {
|
||||
try {
|
||||
$("#coqui_api_model_install_status").text("Downloading model...");
|
||||
$("#coqui_api_model_install_button").hide();
|
||||
@ -449,33 +561,33 @@ class CoquiTtsProvider {
|
||||
let apiResult = await CoquiTtsProvider.installModel(model_id, action);
|
||||
apiResult = await apiResult.json();
|
||||
|
||||
console.debug(DEBUG_PREFIX,"Response:",apiResult);
|
||||
console.debug(DEBUG_PREFIX, "Response:", apiResult);
|
||||
|
||||
if (apiResult["status"] == "done") {
|
||||
$("#coqui_api_model_install_status").text("Model installed and ready to use!");
|
||||
$("#coqui_api_model_install_button").hide();
|
||||
onModelNameChange_pointer();
|
||||
}
|
||||
|
||||
|
||||
if (apiResult["status"] == "downloading") {
|
||||
toastr.error("Check extras console for progress", DEBUG_PREFIX+" already downloading", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
toastr.error("Check extras console for progress", DEBUG_PREFIX + " already downloading", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
$("#coqui_api_model_install_status").text("Already downloading a model, check extras console!");
|
||||
$("#coqui_api_model_install_button").show();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
toastr.error(error, DEBUG_PREFIX+" error with model download", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
toastr.error(error, DEBUG_PREFIX + " error with model download", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
|
||||
onModelNameChange_pointer();
|
||||
}
|
||||
// will refresh model status
|
||||
// will refresh model status
|
||||
});
|
||||
|
||||
|
||||
$("#coqui_api_model_install_button").show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//#############################//
|
||||
// API Calls //
|
||||
@ -501,7 +613,7 @@ class CoquiTtsProvider {
|
||||
});
|
||||
|
||||
if (!apiResult.ok) {
|
||||
toastr.error(apiResult.statusText, DEBUG_PREFIX+' Check model state request failed');
|
||||
toastr.error(apiResult.statusText, DEBUG_PREFIX + ' Check model state request failed');
|
||||
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`);
|
||||
}
|
||||
|
||||
@ -526,14 +638,40 @@ class CoquiTtsProvider {
|
||||
});
|
||||
|
||||
if (!apiResult.ok) {
|
||||
toastr.error(apiResult.statusText, DEBUG_PREFIX+' Install model '+model_id+' request failed');
|
||||
toastr.error(apiResult.statusText, DEBUG_PREFIX + ' Install model ' + model_id + ' request failed');
|
||||
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`);
|
||||
}
|
||||
|
||||
return apiResult
|
||||
}
|
||||
|
||||
// Get speakers
|
||||
/*
|
||||
Retrieve user custom models
|
||||
*/
|
||||
static async getLocalModelList() {
|
||||
throwIfModuleMissing()
|
||||
const url = new URL(getApiUrl());
|
||||
url.pathname = '/api/text-to-speech/coqui/local/get-models';
|
||||
|
||||
const apiResult = await doExtrasFetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"model_id": "model_id",
|
||||
"action": "action"
|
||||
})
|
||||
})
|
||||
|
||||
if (!apiResult.ok) {
|
||||
toastr.error(apiResult.statusText, DEBUG_PREFIX + ' Get local model list request failed');
|
||||
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`);
|
||||
}
|
||||
|
||||
return apiResult
|
||||
}
|
||||
|
||||
|
||||
// Expect voiceId format to be like:
|
||||
@ -547,10 +685,10 @@ class CoquiTtsProvider {
|
||||
|
||||
let language = "none"
|
||||
let speaker = "none"
|
||||
const tokens = voiceId.replaceAll("]","").replaceAll("\"","").split("[");
|
||||
const tokens = voiceId.replaceAll("]", "").replaceAll("\"", "").split("[");
|
||||
const model_id = tokens[0]
|
||||
|
||||
console.debug(DEBUG_PREFIX,"Preparing TTS request for",tokens)
|
||||
console.debug(DEBUG_PREFIX, "Preparing TTS request for", tokens)
|
||||
|
||||
// First option
|
||||
if (tokens.length > 1) {
|
||||
@ -590,12 +728,12 @@ class CoquiTtsProvider {
|
||||
|
||||
// Dirty hack to say not implemented
|
||||
async fetchTtsVoiceIds() {
|
||||
return [{name:"Voice samples not implemented for coqui TTS yet, search for the model samples online", voice_id:"",lang:"",}]
|
||||
return [{ name: "Voice samples not implemented for coqui TTS yet, search for the model samples online", voice_id: "", lang: "", }]
|
||||
}
|
||||
|
||||
// Do nothing
|
||||
previewTtsVoice(id) {
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
async fetchTtsFromHistory(history_item_id) {
|
||||
@ -609,10 +747,34 @@ class CoquiTtsProvider {
|
||||
|
||||
async function moduleWorker() {
|
||||
updateCharactersList();
|
||||
|
||||
if (!modules.includes('coqui-tts'))
|
||||
return
|
||||
|
||||
// Initialized local model once
|
||||
if (!coquiLocalModelsReceived) {
|
||||
let result = await CoquiTtsProvider.getLocalModelList();
|
||||
result = await result.json();
|
||||
|
||||
coquiLocalModels = result["models_list"];
|
||||
|
||||
$("#coqui_local_model_name").show();
|
||||
$('#coqui_local_model_name')
|
||||
.find('option')
|
||||
.remove()
|
||||
.end()
|
||||
.append('<option value="none">Select model</option>')
|
||||
.val('none');
|
||||
|
||||
for (const model_dataset of coquiLocalModels)
|
||||
$("#coqui_local_model_name").append(new Option(model_dataset, model_dataset));
|
||||
|
||||
coquiLocalModelsReceived = true;
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
const wrapper = new ModuleWorkerWrapper(moduleWorker);
|
||||
setInterval(wrapper.update.bind(wrapper), UPDATE_INTERVAL);
|
||||
moduleWorker();
|
||||
})
|
||||
})
|
||||
|
@ -27,11 +27,11 @@
|
||||
"glow-tts": {
|
||||
"id": "tts_models/en/ljspeech/glow-tts"
|
||||
},
|
||||
"vits": {
|
||||
"id": "tts_models/en/ljspeech/vits"
|
||||
},
|
||||
"speedy-speech": {
|
||||
"id": "tts_models/en/ljspeech/speedy-speech"
|
||||
},
|
||||
"vits": {
|
||||
"id": "tts_models/en/ljspeech/vits"
|
||||
}
|
||||
},
|
||||
"vctk": {
|
||||
|
@ -0,0 +1,870 @@
|
||||
{
|
||||
"multilingual": {
|
||||
"multi-dataset": {
|
||||
"your_tts": {
|
||||
"id": "tts_models/multilingual/multi-dataset/your_tts",
|
||||
"languages": [
|
||||
"en",
|
||||
"fr-fr",
|
||||
"pt-br"
|
||||
],
|
||||
"speakers": [
|
||||
"female-en-5",
|
||||
"female-en-5\n",
|
||||
"female-pt-4\n",
|
||||
"male-en-2",
|
||||
"male-en-2\n",
|
||||
"male-pt-3\n"
|
||||
]
|
||||
},
|
||||
"bark": {
|
||||
"id": "tts_models/multilingual/multi-dataset/bark"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bg": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/bg/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"cs": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/cs/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"da": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/da/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"et": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/et/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ga": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/ga/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"ek1": {
|
||||
"tacotron2": {
|
||||
"id": "tts_models/en/ek1/tacotron2"
|
||||
}
|
||||
},
|
||||
"ljspeech": {
|
||||
"tacotron2-DDC": {
|
||||
"id": "tts_models/en/ljspeech/tacotron2-DDC"
|
||||
},
|
||||
"tacotron2-DDC_ph": {
|
||||
"id": "tts_models/en/ljspeech/tacotron2-DDC_ph"
|
||||
},
|
||||
"glow-tts": {
|
||||
"id": "tts_models/en/ljspeech/glow-tts"
|
||||
},
|
||||
"speedy-speech": {
|
||||
"id": "tts_models/en/ljspeech/speedy-speech"
|
||||
},
|
||||
"tacotron2-DCA": {
|
||||
"id": "tts_models/en/ljspeech/tacotron2-DCA"
|
||||
},
|
||||
"vits": {
|
||||
"id": "tts_models/en/ljspeech/vits"
|
||||
},
|
||||
"vits--neon": {
|
||||
"id": "tts_models/en/ljspeech/vits--neon"
|
||||
},
|
||||
"fast_pitch": {
|
||||
"id": "tts_models/en/ljspeech/fast_pitch"
|
||||
},
|
||||
"overflow": {
|
||||
"id": "tts_models/en/ljspeech/overflow"
|
||||
},
|
||||
"neural_hmm": {
|
||||
"id": "tts_models/en/ljspeech/neural_hmm"
|
||||
}
|
||||
},
|
||||
"vctk": {
|
||||
"vits": {
|
||||
"id": "tts_models/en/vctk/vits",
|
||||
"speakers": [
|
||||
"ED\n",
|
||||
"p225",
|
||||
"p226",
|
||||
"p227",
|
||||
"p228",
|
||||
"p229",
|
||||
"p230",
|
||||
"p231",
|
||||
"p232",
|
||||
"p233",
|
||||
"p234",
|
||||
"p236",
|
||||
"p237",
|
||||
"p238",
|
||||
"p239",
|
||||
"p240",
|
||||
"p241",
|
||||
"p243",
|
||||
"p244",
|
||||
"p245",
|
||||
"p246",
|
||||
"p247",
|
||||
"p248",
|
||||
"p249",
|
||||
"p250",
|
||||
"p251",
|
||||
"p252",
|
||||
"p253",
|
||||
"p254",
|
||||
"p255",
|
||||
"p256",
|
||||
"p257",
|
||||
"p258",
|
||||
"p259",
|
||||
"p260",
|
||||
"p261",
|
||||
"p262",
|
||||
"p263",
|
||||
"p264",
|
||||
"p265",
|
||||
"p266",
|
||||
"p267",
|
||||
"p268",
|
||||
"p269",
|
||||
"p270",
|
||||
"p271",
|
||||
"p272",
|
||||
"p273",
|
||||
"p274",
|
||||
"p275",
|
||||
"p276",
|
||||
"p277",
|
||||
"p278",
|
||||
"p279",
|
||||
"p280",
|
||||
"p281",
|
||||
"p282",
|
||||
"p283",
|
||||
"p284",
|
||||
"p285",
|
||||
"p286",
|
||||
"p287",
|
||||
"p288",
|
||||
"p292",
|
||||
"p293",
|
||||
"p294",
|
||||
"p295",
|
||||
"p297",
|
||||
"p298",
|
||||
"p299",
|
||||
"p300",
|
||||
"p301",
|
||||
"p302",
|
||||
"p303",
|
||||
"p304",
|
||||
"p305",
|
||||
"p306",
|
||||
"p307",
|
||||
"p308",
|
||||
"p310",
|
||||
"p311",
|
||||
"p312",
|
||||
"p313",
|
||||
"p314",
|
||||
"p316",
|
||||
"p317",
|
||||
"p318",
|
||||
"p323",
|
||||
"p326",
|
||||
"p329",
|
||||
"p330",
|
||||
"p333",
|
||||
"p334",
|
||||
"p335",
|
||||
"p336",
|
||||
"p339",
|
||||
"p340",
|
||||
"p341",
|
||||
"p343",
|
||||
"p345",
|
||||
"p347",
|
||||
"p351",
|
||||
"p360",
|
||||
"p361",
|
||||
"p362",
|
||||
"p363",
|
||||
"p364",
|
||||
"p374",
|
||||
"p376"
|
||||
]
|
||||
},
|
||||
"fast_pitch": {
|
||||
"id": "tts_models/en/vctk/fast_pitch",
|
||||
"speakers": [
|
||||
"VCTK_p225",
|
||||
"VCTK_p226",
|
||||
"VCTK_p227",
|
||||
"VCTK_p228",
|
||||
"VCTK_p229",
|
||||
"VCTK_p230",
|
||||
"VCTK_p231",
|
||||
"VCTK_p232",
|
||||
"VCTK_p233",
|
||||
"VCTK_p234",
|
||||
"VCTK_p236",
|
||||
"VCTK_p237",
|
||||
"VCTK_p238",
|
||||
"VCTK_p239",
|
||||
"VCTK_p240",
|
||||
"VCTK_p241",
|
||||
"VCTK_p243",
|
||||
"VCTK_p244",
|
||||
"VCTK_p245",
|
||||
"VCTK_p246",
|
||||
"VCTK_p247",
|
||||
"VCTK_p248",
|
||||
"VCTK_p249",
|
||||
"VCTK_p250",
|
||||
"VCTK_p251",
|
||||
"VCTK_p252",
|
||||
"VCTK_p253",
|
||||
"VCTK_p254",
|
||||
"VCTK_p255",
|
||||
"VCTK_p256",
|
||||
"VCTK_p257",
|
||||
"VCTK_p258",
|
||||
"VCTK_p259",
|
||||
"VCTK_p260",
|
||||
"VCTK_p261",
|
||||
"VCTK_p262",
|
||||
"VCTK_p263",
|
||||
"VCTK_p264",
|
||||
"VCTK_p265",
|
||||
"VCTK_p266",
|
||||
"VCTK_p267",
|
||||
"VCTK_p268",
|
||||
"VCTK_p269",
|
||||
"VCTK_p270",
|
||||
"VCTK_p271",
|
||||
"VCTK_p272",
|
||||
"VCTK_p273",
|
||||
"VCTK_p274",
|
||||
"VCTK_p275",
|
||||
"VCTK_p276",
|
||||
"VCTK_p277",
|
||||
"VCTK_p278",
|
||||
"VCTK_p279",
|
||||
"VCTK_p280",
|
||||
"VCTK_p281",
|
||||
"VCTK_p282",
|
||||
"VCTK_p283",
|
||||
"VCTK_p284",
|
||||
"VCTK_p285",
|
||||
"VCTK_p286",
|
||||
"VCTK_p287",
|
||||
"VCTK_p288",
|
||||
"VCTK_p292",
|
||||
"VCTK_p293",
|
||||
"VCTK_p294",
|
||||
"VCTK_p295",
|
||||
"VCTK_p297",
|
||||
"VCTK_p298",
|
||||
"VCTK_p299",
|
||||
"VCTK_p300",
|
||||
"VCTK_p301",
|
||||
"VCTK_p302",
|
||||
"VCTK_p303",
|
||||
"VCTK_p304",
|
||||
"VCTK_p305",
|
||||
"VCTK_p306",
|
||||
"VCTK_p307",
|
||||
"VCTK_p308",
|
||||
"VCTK_p310",
|
||||
"VCTK_p311",
|
||||
"VCTK_p312",
|
||||
"VCTK_p313",
|
||||
"VCTK_p314",
|
||||
"VCTK_p316",
|
||||
"VCTK_p317",
|
||||
"VCTK_p318",
|
||||
"VCTK_p323",
|
||||
"VCTK_p326",
|
||||
"VCTK_p329",
|
||||
"VCTK_p330",
|
||||
"VCTK_p333",
|
||||
"VCTK_p334",
|
||||
"VCTK_p335",
|
||||
"VCTK_p336",
|
||||
"VCTK_p339",
|
||||
"VCTK_p340",
|
||||
"VCTK_p341",
|
||||
"VCTK_p343",
|
||||
"VCTK_p345",
|
||||
"VCTK_p347",
|
||||
"VCTK_p351",
|
||||
"VCTK_p360",
|
||||
"VCTK_p361",
|
||||
"VCTK_p362",
|
||||
"VCTK_p363",
|
||||
"VCTK_p364",
|
||||
"VCTK_p374",
|
||||
"VCTK_p376"
|
||||
]
|
||||
}
|
||||
},
|
||||
"sam": {
|
||||
"tacotron-DDC": {
|
||||
"id": "tts_models/en/sam/tacotron-DDC"
|
||||
}
|
||||
},
|
||||
"blizzard2013": {
|
||||
"capacitron-t2-c50": {
|
||||
"id": "tts_models/en/blizzard2013/capacitron-t2-c50"
|
||||
},
|
||||
"capacitron-t2-c150_v2": {
|
||||
"id": "tts_models/en/blizzard2013/capacitron-t2-c150_v2"
|
||||
}
|
||||
},
|
||||
"multi-dataset": {
|
||||
"tortoise-v2": {
|
||||
"id": "tts_models/en/multi-dataset/tortoise-v2"
|
||||
}
|
||||
},
|
||||
"jenny": {
|
||||
"jenny": {
|
||||
"id": "tts_models/en/jenny/jenny"
|
||||
}
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"mai": {
|
||||
"tacotron2-DDC": {
|
||||
"id": "tts_models/es/mai/tacotron2-DDC"
|
||||
}
|
||||
},
|
||||
"css10": {
|
||||
"vits": {
|
||||
"id": "tts_models/es/css10/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"mai": {
|
||||
"tacotron2-DDC": {
|
||||
"id": "tts_models/fr/mai/tacotron2-DDC"
|
||||
}
|
||||
},
|
||||
"css10": {
|
||||
"vits": {
|
||||
"id": "tts_models/fr/css10/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"uk": {
|
||||
"mai": {
|
||||
"glow-tts": {
|
||||
"id": "tts_models/uk/mai/glow-tts"
|
||||
},
|
||||
"vits": {
|
||||
"id": "tts_models/uk/mai/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"zh-CN": {
|
||||
"baker": {
|
||||
"tacotron2-DDC-GST": {
|
||||
"id": "tts_models/zh-CN/baker/tacotron2-DDC-GST"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nl": {
|
||||
"mai": {
|
||||
"tacotron2-DDC": {
|
||||
"id": "tts_models/nl/mai/tacotron2-DDC"
|
||||
}
|
||||
},
|
||||
"css10": {
|
||||
"vits": {
|
||||
"id": "tts_models/nl/css10/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"de": {
|
||||
"thorsten": {
|
||||
"tacotron2-DCA": {
|
||||
"id": "tts_models/de/thorsten/tacotron2-DCA"
|
||||
},
|
||||
"vits": {
|
||||
"id": "tts_models/de/thorsten/vits"
|
||||
},
|
||||
"tacotron2-DDC": {
|
||||
"id": "tts_models/de/thorsten/tacotron2-DDC"
|
||||
}
|
||||
},
|
||||
"css10": {
|
||||
"vits-neon": {
|
||||
"id": "tts_models/de/css10/vits-neon"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"kokoro": {
|
||||
"tacotron2-DDC": {
|
||||
"id": "tts_models/ja/kokoro/tacotron2-DDC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tr": {
|
||||
"common-voice": {
|
||||
"glow-tts": {
|
||||
"id": "tts_models/tr/common-voice/glow-tts"
|
||||
}
|
||||
}
|
||||
},
|
||||
"it": {
|
||||
"mai_female": {
|
||||
"glow-tts": {
|
||||
"id": "tts_models/it/mai_female/glow-tts"
|
||||
},
|
||||
"vits": {
|
||||
"id": "tts_models/it/mai_female/vits"
|
||||
}
|
||||
},
|
||||
"mai_male": {
|
||||
"glow-tts": {
|
||||
"id": "tts_models/it/mai_male/glow-tts"
|
||||
},
|
||||
"vits": {
|
||||
"id": "tts_models/it/mai_male/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ewe": {
|
||||
"openbible": {
|
||||
"vits": {
|
||||
"id": "tts_models/ewe/openbible/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"hau": {
|
||||
"openbible": {
|
||||
"vits": {
|
||||
"id": "tts_models/hau/openbible/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lin": {
|
||||
"openbible": {
|
||||
"vits": {
|
||||
"id": "tts_models/lin/openbible/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tw_akuapem": {
|
||||
"openbible": {
|
||||
"vits": {
|
||||
"id": "tts_models/tw_akuapem/openbible/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tw_asante": {
|
||||
"openbible": {
|
||||
"vits": {
|
||||
"id": "tts_models/tw_asante/openbible/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"yor": {
|
||||
"openbible": {
|
||||
"vits": {
|
||||
"id": "tts_models/yor/openbible/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"hu": {
|
||||
"css10": {
|
||||
"vits": {
|
||||
"id": "tts_models/hu/css10/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"el": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/el/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fi": {
|
||||
"css10": {
|
||||
"vits": {
|
||||
"id": "tts_models/fi/css10/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"hr": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/hr/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lt": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/lt/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lv": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/lv/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mt": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/mt/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pl": {
|
||||
"mai_female": {
|
||||
"vits": {
|
||||
"id": "tts_models/pl/mai_female/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pt": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/pt/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ro": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/ro/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sk": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/sk/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sl": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/sl/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sv": {
|
||||
"cv": {
|
||||
"vits": {
|
||||
"id": "tts_models/sv/cv/vits"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ca": {
|
||||
"custom": {
|
||||
"vits": {
|
||||
"id": "tts_models/ca/custom/vits",
|
||||
"speakers": [
|
||||
"00236e350cc84b94a6684f182acf96e68963d7fa1164d4fa56da20f46f210b2dd3ecf189e97fb3c94113a54c12dc20550508f5b7b9b37e1873898d58a308feb5",
|
||||
"00459",
|
||||
"00762",
|
||||
"00983a845f95493fb27125b114c635f3b40060efaee167d32d8a3dd040c877713446c7bd3e6944641227bdb4165ecb8d684ec2ef66c817e65e77c52cc50e62ed",
|
||||
"01591",
|
||||
"02452",
|
||||
"02689",
|
||||
"02992",
|
||||
"02f7d61edf5063ca42953b1068539f1572985aa9448555cfd8d7667121eeedc72c912d95cf33abf61a1f9620f2a01be4251a53aa5440d15849003fb31210d830",
|
||||
"03115",
|
||||
"03386",
|
||||
"03655",
|
||||
"03944",
|
||||
"04247",
|
||||
"04484",
|
||||
"04787",
|
||||
"04910",
|
||||
"05147",
|
||||
"056d7638d714a7dc1efe1c47d390d0659fbfdfc7df5249e8bfe10ba346cc76d5cda93fc8ecbeadffd4924c4f9cfb6b32c1739c8af1e2d58d7cec88b2cf18795f",
|
||||
"05739",
|
||||
"06008",
|
||||
"06042",
|
||||
"06279",
|
||||
"06311",
|
||||
"06582",
|
||||
"06705",
|
||||
"06942",
|
||||
"06c6d2e093624103c268e2cba37466147fd564bff1312a78d1c5be9ba168af4cf4819c7a91d5321d7aa9bd20ad6c702ca2cb005496dd20c45d293200b2b8a7b9",
|
||||
"07140",
|
||||
"07245",
|
||||
"07803",
|
||||
"08001",
|
||||
"08106",
|
||||
"085503e68b0772f1b3aa4de86a57bb26e3750660e7929a14a653c729787a110cc8b3704f8ea09842f72be46b6ffbb35bdb3732308b31dceefc3b33e5ad3f7975",
|
||||
"08664",
|
||||
"08935",
|
||||
"08967",
|
||||
"09204",
|
||||
"09598",
|
||||
"09901",
|
||||
"0befb1084ad00d656f45a87ad83f074c61e3b3767cf6f5463fd5bc199ab7fd4733c5f02e3a100359e953977cc2a2689bd4824ef6e3178a7108cb45a0204fb3cb",
|
||||
"0c6bf67821762116d753c9b48ebed8a2ccfa0a956d5dbf19feb0ac0bc2096154ca288ae7c5e324a3092db395cc24c64c6a4e4fb0e01429b7343cafc7ac1b2e13",
|
||||
"0d0a943d348b4f0948da443c4d020b2e690731955ce8c318c0fb72663cfec3cd3458488ff9ff9cee6d221c85771b8eb83cc087dda37d4109bbb1614039e5f565",
|
||||
"0da83aed14276e120e2581be32891bb088a22c272feb6f03b4bac1b827cccdbc8fee277a885f58e98931819e0d6171526c5fa7b2e788f68a2852e4d5314f613b",
|
||||
"0ff19536d6147f61b24d50c0c993a7a687df4d253c2052e4fa30b1624c87e60075649d888f51ce71318fb8789cb378879091aba020256d66ac19f024833c3e63",
|
||||
"125d9d1721de26a9b89d0e4f4d386e07458d287ebb2f338879e8886847abe6b3209f79e2bc335bcfc437350184df5a7d9e1a08ffb5239674edfd1cf95a9d1e24",
|
||||
"1378866a4d2b6965c03eed8e48e03fffd089638acdf1fa82ed20a9856406e083f0c0e1f5043c4d3bf67dbc383f7cd28b602eff1d8bd8bf8c1a0191dc98540322",
|
||||
"14bc32c10eb26503a4e799c3a762bfe5949d7a232074e854ecfad8139acaa4257c563a502e06a263f2d5fa8337114a9741d4a634a0f914adae74e5f9a80f145f",
|
||||
"151fcb1168f41a51c49e20b426605109e1d9dd50be2926aa9878040fe325eba2f2c470357a735e9e24b7412e78e2550a8fbd0ea77fed80e4d8f50a21f2064948",
|
||||
"1610e29603954ee12f408eaeb83a5c99781b5efe5f64fdf2e3c5e0ba9756b5b11bfeefda40a787842f7d5da653135043e3f43e7f786499cb51ad6181ef8acc9d",
|
||||
"1887c37f4187a4c3213ba4b58d0ef15f903a3720ee94d5ce59c33db193f60db416a4d9607f213ae44ca3eafc7217fb9871e2ee1837ad4cc0f34794e5c543f9f5",
|
||||
"1add23d44d2d913f0ea6e061fe292b0563653fa15b4ecc9cce0c2b83dc5a743d6d3dd4625efa112f751852c348a667a9456ef3486ae7e8c5954dedc69f998ea2",
|
||||
"1b7fc0c4e437188bdf1b03ed21d45b780b525fd0dc3900b9759d0755e34bc25e31d64e69c5bd547ed0eda67d104fc0d658b8ec78277810830167c53ef8ced24b",
|
||||
"1b8354b1fe9255578225b3d2255d5e781eed7d13ab61e84bc08be5d6465ec468c533563137ca756fcb7d3759af0ac2c0b4d00873782c7bf47ea72fd9be2f9e8c",
|
||||
"1be6c773da6334cc73e23312689bc8a5915529c905e1d5289dbfe00332a7dcb9ae97efe209635e2e5040783777409155926d231a5a5f76357494671512d2b1a4",
|
||||
"1c7af1cc1357fd63bd9ffe915745e20c34588438e1e0d85fdc8c9de4b3bd41d3d61b318b6a69862c6d64dd41f15ef3d994a6bb6c9a9dac69c891308b09ab16a5",
|
||||
"1c7f19a7fa0b166c700bac583b6858ce7adbe19566d66e530953273aae59776757aebaeb30c20a58d74bc50ce1345516af5bbd36168f443fed809bf54c02f63c",
|
||||
"1c80e9d982aa0c12db8498e8275b2281e638e8e5c684a752e19f8f9842979b70a3624785d0c30e0e57112950cae5e892bf554c295c74cf8c82c8ec33c732d8c6",
|
||||
"2256cc5ee6c617347af9a1abd97dfe80f55e6691eb0a042321d46a1bd7ce0baf1c7a4c8ea3fe4184f8638b1c3d9e83b6aa193bd6f9b49d5358523f1fe324cd92",
|
||||
"238532dddf77923ce93cf2e9ed809d088094106a1aad327e8a7b229ce24a339771e59478f7d5162efc1da6f347b44cbb2273ac9154aa3a76c7a8fc458470cc2b",
|
||||
"241ca4fdf2124f550657446301fb8dfc8bdef46d3888ce39bf9d8622c2bbec7e06b198f5e33fadbf30e477fdb37435cea36d10341af1a7d3a80d0ad1caa94bf9",
|
||||
"2421aa51a089ecfe45250bf284d5690a9994a9eb03f2ba4f43d2ad73fe78783ae5f3d3088d772e01fd1d747b2ecd6bb1bfae5feb10a72130d3952ba7304d5c53",
|
||||
"24d967d0e8b84beb3652417724be81ab83c7834afaa7b7d3d7d9591b1a2a7bb75f9b25be548a200570ebd6cc34e91306b675af510ef91cd34a77060b65b9faaa",
|
||||
"25911630ab15956e81427d3e990cf37f79490e305914a15ca7dd7b95dd4d4feb15fd94549cc005376801ce68d637eab6e19ee36017dba5c01bd0f206e5e8dc3b",
|
||||
"26099adbc4db8fcf000e2c7d1da3399662281f9af03831808d29c602431af4fc13f21b38c5c42c5ac4f77ece48448eef99f735d92cdaed857d19da7dd2b888ad",
|
||||
"28e2fe1944a593c44c3de0dc52971f040f0b8901fced2057025bdbafa1fe3b042be19618044ae085d7364e3cb38601e9ce4030329f15af7a0898f9d4c2c5014f",
|
||||
"2b59e9f830e5ea00c500b63eff4e72553e0c2608f5741d35c226e733400412014d7697bd6efb67bc61b19fd61e40f9ed70fde2589fe0b5498915eebc1c8b5d93",
|
||||
"2bc2a177bf56dcc98e05501e7bc6eebd3d1662114764299a4f9e6b060a48095b8ec95d20a5814f71343d65ee3cd2e7f42a80faa51a148005242cc5073e605ba4",
|
||||
"2ce84c6ea6aae52c449b6d34cbc095b2f2c3e6fa20d0e48b2f7d223724ae01375e92a8ad106b029f0562ee735de36d9bca6cd167257c3f68796bd8b1a0ab600f",
|
||||
"2d84f39c2cca33dd28fee650caa022c9a06407462342fae8dc256af7904cdd114af5b4cc883181407b8dcf2dc4a93d45c62c83a317d84e876cf710a521f20d80",
|
||||
"2e6ccdf9f0a7bf0df6fd0572bbb53f25378fc5333b352bc885b3a0d01e5dd672156cf697c127cc998ac546d122c547c421970a6f23dccb60bf2c841146fa6576",
|
||||
"2f92b4704080216aa80b1b39cfa223feeb9ed7c909f5b77be1b6e45fdc8827463bc4c4cd98263f02b57e653ecc2ccc7192aedd92990113433077e7ed44eb1e0a",
|
||||
"2fb95c3b786fa65215534207266e034b294317b2327ee0928be3436258e42db8f4479e86e6006979ec4438dbaa9daa05be21ddc66717d30dc43e36ead349965e",
|
||||
"30b1f81c579755895581259d79a8a5a3ca45b908b0bd14ad1c6418f39aa1e2f47cb4749c69b5440cdb92e3bafb772e19e7bc2b16d196b061addd173a1309e491",
|
||||
"31535cb2ece4710d08fdbeefb6f8f75ed093fee4cf8573bd601d960f8c6156f0fd0a85712761691e86e31160b993ee0eacb10c4c8aed000cc394cf7c7d207a7e",
|
||||
"31e6f3a011661320b2e59b6f8be43f6db2243e9feabc2b9787c1413788e13eb0e5810bed983bf7ff66e46417d183a91ed50b3b9be9d89e4f51aada72293b9881",
|
||||
"32550810ba55b9a67a25d308f0ede521f12cbf6076472ff5bd60a8f5e951c481b784e2f04194fb96116c4f001d84b3993b2c580879671de46333d5f212ff2ca5",
|
||||
"336f82b4645b80c99137018e69bb6f8138a9c8dc05a510e36922503120648625674e1414cd90d0cf46f28cbd5993ae0eaedc9994b72e8eb5242737ddefc0bfb2",
|
||||
"35b962b08846ed7d8a4cc47582a4e607f5ff4136042ce0b1adb55d1e8d58e2dc1abc5807b3601a7f7be1ada5939e1771e128fc916c1b5d39ed3619e251707952",
|
||||
"3637902e0d19f0080313c14d2c9dcde800ec6b71d493459c2f3b2cebf186f028ea289dd59ba1fd4705e53891216f7f4c36dbcb8938aeeaf142317b441b20a837",
|
||||
"3723bd65a05afc7411c2bfca904742062b7b0c081ba126e68c65d28eaa6122f69196f4959fc1795fe03f8e49ec7364863911f9b659684a06b3a126c6f1729551",
|
||||
"373d86f9fa3a127372dd913b7571ed318bfea42173b2b7daebde93c742f3224fb7fe5306085e836d20bfee4201bfe070b4c6b36510f5c9f379f6a3b610f36cd0",
|
||||
"379d321bff71ebcd34792e8f4552d341f30a006b4765f8c6de4fa98d3ca416def88adbcb0253f5849f51793b3d7ca7e53700ec70b5a97e84ccd1f35a2a1fb6e5",
|
||||
"37c12c700c95dc0028b3b82c4cf1fb922d68680c35fe84585bf22674e71c4dc53bd9233ce8b71bd31e9c9b0e000d01d195a3572b9055a73fbec891b1ade250cf",
|
||||
"3a4a32c7cff18f1896e7cbff2c19b4e6f91a95c1e7aab616722600ceb36a86b07fb0e1e0c70cc285dfb6192b53cb67826698b7f3f652549e27a969bde0177fa7",
|
||||
"404ecea5ae8e5f4ec3d2c48494cf7f1d559268542d8f1f7928da2fcde55c9fa3f491ba632f555ec69e8c9e819072df450add7e5886cf5527f446b11544af7d05",
|
||||
"41e5e21b3a3b0c8df01ba5b3c3e6224cc4082f41ca87679344b0273e2216cc272e19426c160f5a9580915c057a3e4000788be6cc7a6f5f346cad5068c7884ce7",
|
||||
"464d9ac63f7958200bc09a141171355bf4f3631d66dc4bbfabd497619a8f055c034c0752987944b2102e02d4b435bcd3ce0527962871112049e1d26865b776e9",
|
||||
"4869d94d4936ab700c5e5bc7b666177b53220082f5f221774b5625d7275cd4f117482dcd1498674b7f885fa41d86f99b8d00b6a6f641829780946651f561fc22",
|
||||
"496b66c9cb705a46cdfef9eeaf29c9d738a4b70b601270985a7df5a06f9e1d6c56be0982995c8cc06902d0ee89bae201c37a91f568331ffe28ad2d150e183fed",
|
||||
"49a7654071536ed5882b8b6e6d2e3558ef796ecd8aab8ceaa24ad8bc9f3420b528ef1413696584c11facd6d5bccd37fe8e274b8c3d139dc251ffb11c3a503aaa",
|
||||
"4b6c7e4e9bde35c471cbf5e2e93b2eb8bbba52b710acecf99910af08b3b35365f24d883ddfdd9825918c31477a5f3fc48f075080c4e97e80fecd6e1936bc92eb",
|
||||
"4bce212aca40bd1834bf741e47954526a8817ecbff8fedda854dbfc2d033a2567bd34b84fa02c3d07855f3dcf413590ae75ad6edf261d66bffb84d77803a7b76",
|
||||
"4cedaa8d96436fd0d2ebdb61d616790a3cb3737d0a93d2ae41d588137c0d3339999d991b7b3c452704be1f5f512ce5a08c0971898fad0ad77f18fd623411cd7f",
|
||||
"4d7e2548403c7e04d809030aa25015c9706e773517e1f72b81bdda22213aeb8f542cc62156bc5ef1c1622e99227fedbcc9c1b3e5e147b854e3b629f8f78bd158",
|
||||
"4de9f262eee7ee7d24ef8933af4610a1c5b97ff055c4fd0f97868e338a017308d460f4b003b74bd2aba7789153593f3b986b814fd93f2e4dfa5b55594fb17c55",
|
||||
"4e5e58a6ec7d9cac969f99b817f981ab7f8d2cbd9ab9dd0a37e45c70a8a8ca3b8e1c43b2013082062ffc1f4f3b268ea78ebb88d613d026a6312f40a6867a1d0b",
|
||||
"4ec8f1e81d7abd9d2dcb3dbd4be86b615f643386f3b1098c37a02a103fe6b36239c05bff6746ce568ca81765b285c1c271af4fb1fd99120341cae2851b776bbb",
|
||||
"4f57d1abde3364d91128e682ba724e6d3bc2ed6b112d2cd679739e478ea6bd671c527edff64c6a7b5c1173f68e02a410f09c2256356fde7d517908310c118382",
|
||||
"503dbbe83f0154e9bba4bc685bf1c1fbdd27293d0e4f837947910e4d320bc4d5bed1ade67a45b541013189a2c133f6f9f6cbc3566fad220c0635f286feec74c5",
|
||||
"51795e8ea8faa28e88f02559f6bdd47d9a0735589d47dd0f2e057b8b01fd3667fd9fd29e2613f200174af1d4b2d3d0860704cebebf2b6e79f1724d6782d7a270",
|
||||
"52cfac480c0cbc60068305d983adbf98814d2cfddb8be0ccfeb7c7f95bdaf31a5f70da944cc2453e6a5fbb9bb4092e36b662e838762855fb016f55e6e3d957c1",
|
||||
"537e815df93312978a9ba479ff2dffc9975c875950a203e8a1b7ffe4cb06625964f59dde1a06b87921a2a91702cc6bab04e159aec7cb2e2fc576cbe25838df2b",
|
||||
"547dd49c2cbe113b60c9df4a8e8b83a532f0da054cea8f1d23db66cc2638f7b5edfee820b4764646be10dbcd05caa5d71483477718a73ce8dfc752204807d9e5",
|
||||
"54f344faa37da0c9ab1ab563735c532ab81fcd1c8431cd8eca4ab7a8774f194e1ffe922547ea42bd1fad36e7493761992eca4821138ded1a9580e9fa38685291",
|
||||
"56071bfe30e977f201fa4d6808f8d7c2f3e6788ba68d12e2eb18386ac2507bb2bbe3c14bab90370066bbf6e2af42afcf1e45b362dba958d38fbc69cdea3874ea",
|
||||
"57e5f7cc5fac058f7c772eb41f8d49bd0fe3070c41eef445b1c073abf9b1cec451aa22764490b7da4c5bcacf4ee453c3153158cb1569f2f9447807cb14dc1126",
|
||||
"5a9a6481f1365def2919871790a95fdccbae145640f3b4b5e11d1d1370ed35c5a4c31e402b3b438892a6bfd9dfbbe2fc97056d2cc24f2ac412b3a5e1adb7003a",
|
||||
"5ba168675a3f2ea8d6d51896c5db84ee59ca65359b1b97e6d79543a6c918fe427f8b6cec79037c452eb086debe1d57049c25481d61a873f0503703266bf0cb84",
|
||||
"5da56ed896575439b7bbca20981f0b50618958d94f08b8f47d13774dca3990d4c571be1f4aa2786bf8fcbd1a594336be49cc26d972d5fb0c0682ab4d5b59d19e",
|
||||
"5ebf04dfec6c9b10a6fe7fd03725901973565a13530c20d02b4332670cce9beab185dd0b0f61f4a87f9c3dacc307d06e062d640f6550d9443a4c06a114e5bca5",
|
||||
"620b0d4c3be90f5f77f0cf9f976e5d7f067689884dc857f2b26a6edb40ef4fd2826213b5028900b168e853d036f1741600b236e04d8dcae5fa26cd2b8975ac04",
|
||||
"6323ec0401b28c1b06afa76760b478535101ae48c6c9367491087143287d9ff76b9c00f39dc838cdb20d65eab16622dc85143f5845791bf85705cb4f20975bbe",
|
||||
"633e7303eae41420e558e186308510783f5c234e9c639c0e6f5b6d37fca6bab766c5d475b2f330910bac93cef6982124e73a1b6bab1a2e99a2e5d797f8547c6d",
|
||||
"6688b60c24d068e19487c0b88a8b0a256854d8090ebebfa9a462fe49a77b8e9f303aa02042069cb0d6f227932cb48863758d0b57a18d53125ad39953bac543aa",
|
||||
"6745c47d0bd557c3dbce201697e8a2fbaff9ca52744d6007a636a237b82d1167795a0c0e2e5eb71b7460ed16e3fdcdac1dba1b7a2910d5168416e236c93ccb76",
|
||||
"6892c6ba9f66d0d7aa0445139081dc82a76d9ef8c7bb049a8eaf090f76c06cb4f1db05739038d7e04167569bb6d0fea55fc15343f7c77cd5a3e2d4c5ed068290",
|
||||
"689a213fd2d66b9d3634c9165b316e49ec53ac96131be42226d462ef1bc3ba38651e94698fd6e6f5c6d6c834d2b9a6732be54a8d6273c1025511d795326ffd3e",
|
||||
"696e8808717101399ab7ff16382db411adfadcd60c6a525539b0f8f88d84b448662fbca212b175379ff78ce7b2e64aa4b4e96d1820ade8eb2f742295f744db7c",
|
||||
"6bdec6b6f7e6b5a187feb6537101d90cca1043e34d53e347f2f0b14e701585361fc4a4cd81577b6d4588844fc8bdba8af66155d9eb6c2eefd461e23d0b2b87e4",
|
||||
"6e5948f904b3048511677d23d3cc9bd678739b234170302e1556c1bd1db8cee4243bf5e012a1320b4c50f6276e05cc5f620c461f640ac7413c23524f63f4aac3",
|
||||
"7115c00371f891d0094a716083b978948431509a16d5a9598e78ec12712db46d46f1674312cd31339e2d6118cca5f7a3f82ec25dce861a059ee31d832cd6dcda",
|
||||
"71b67ba5ec75978632136441a25426dbd48d4c0a55c1a5fc91f0f952b6bac06ab0d9709f0a7bb5a05393499135b76e4d722c7065fb636a227ba58c7fb86438eb",
|
||||
"72a3d5bde83f60653937232cf4d29218ff5988533855fdbc804d9bea7e94eb14a8afbe36a8f8ee576a3ed2345632d4ad36df52efdd9adbdb60da6f890074c6b6",
|
||||
"73d3685f3e78183724e3362f6c4288d522b54a8d2722197dc5ff5006974c1529dc562c1cbb05f023da4922cfc04340eb83b887c5343041febed1ddc44b22f9ed",
|
||||
"74a679bf6c4a1b5856a25780496812416383f0567afcbd9b411ae9a0abab47d466741bd925b03decd7da586c6ea9589c8f40208ac2a22fa4413d4ea6e1a6f0dd",
|
||||
"7638395f7d47fbf631633e2b899044e82e7ce0e07305114921cb0696551966b09993766782aaad70fa40a0f7362be31940381653c659fb73d3e1fd1fa45c257d",
|
||||
"76383f56d9979837d4b3348f9f28877dd1ba58c1bd0ea839bdabf021428c2edfba46ff25558004c5183a73575eb126d4e0746a40e22ab15154d5d6f238a48ca5",
|
||||
"77cd12af0a3d1d8cb64dd577bd2d50ac057d816694e8bc04089a6adb90e53ad6cbe9fe6aaf52596450e0c8178d8f9b88a545b27adcbc89bddf4d7c4bc4dd31fd",
|
||||
"7834da277192e9434b0c039272ee6b3f1b225d2f975aa175fee762fb0d5f16b1edba2e0dbf11d8aa2bab5984482f703f88f0e9d1786a7687710ea2688f307ccd",
|
||||
"79a830901c1bb0e27663dbe14d13df91d887daf0eabb6d3eee7f09768212afcd9cdde458d13042a9d2aa099f390c79ab94f2c1ca47fe0321f6c18973e437cdd6",
|
||||
"7b7593f44cc6f9f7b21495bca6f3d564f73f36b97ee15d51a783da8141463834022996c55e494800d21304079aefa8a5fe64350c9273e0d36453b097b2dcc5f4",
|
||||
"7c7d917d97412c24b76af336086469a43013d1d6b27298aa82c4e99b3f3b6c5a82014428a6a14b080a834382d9b0f178e405fb10170bcd340957955087698e19",
|
||||
"7d19dccf48114d3ec00c45fe80581300faca042157d6c9458ec439c300d8c7b1190aa70eecf19f8b1d5af8c7291f3da08fc635a7fd6acc7c5b203d1e226589f5",
|
||||
"7d8d6fa22ff724d823b82499686732b7fbf32f7c1f35dd5733ec3b65fa9625cf2d49bba86e6e0132252bea64074f35ff96a77bfa44441aed3fc1765b13cbc526",
|
||||
"7e36be2204fe367a3798e1b2ff988779890591e5c997b1f6025ec8ee1fef3eb19e81b74bb8657874f5a990d5062d6c849621ce363c4a9c2c5a63c0966be6140c",
|
||||
"7ff908cc2a18ec5a80e74fb4a2f12b406f0b7456ac797d35091d618c7ee991baa88edf62200817aa27732b03d9109cbdc6603092822b2e13a575953045b1cd0a",
|
||||
"8154716e77acd0f5e912887facffc7b2c9889891e863a39fcfed1e5637e47328a4a3bf40bbac1e740629d3013304ada88cf24dbf3735a7aa2d4b855f813c8fd1",
|
||||
"8162d651b6211f06f655a69cd7fdd383d6b4287e9ba132b9898ef9ac8687349e777626333d23bed93f9264aae965efb14ed650cb64fd0ad90494aff903eaef11",
|
||||
"8348c81a253096a9def0b472a8499fc03ef8c6c6d3cc9b4a018f142501ebd04c2479008b88895e033eb83978e7d71e52a91a2e324ca869ed8f2724dfdcef269e",
|
||||
"84b101db8d076398c1d624a8b38b22fbddbfa8fcc43ade44619f5a9b6e70daf1c963d6dc09ea039cca94ec56ccfd04a1689e806c970c0bd32cc9e56b73c7bd7b",
|
||||
"853fb95e0f017c203e08312e3ccf45c0419928e08313b1bb0444aa4ff089550546e67fdd3434a22cae3f67603437051e49be5c4d8fc5583b1aa6a1ae36f0a911",
|
||||
"85c9e13ccfc0d67de10281b04257d8ac0c256d2f9415e54148fb59954c0d43f66d3cbea43ea6389f8407a8bda8b1b1becd30e41dfbb3dd9bebbe69816d096fa9",
|
||||
"85ea0b349a8df04283c62efb571d2947e7264b566883e300501086733b08efa42ced215bc47951c8198626f86ca8c0df730cdc35f4d99ffff958599884b68e51",
|
||||
"88673d4f24d039e89c15d9ede6b653e41e42ca8bd7a8cb7e92a4f235e9b56cbad6200f8dc313c644e9a7d8d1dbc2b7e988da93bc0765499701bca6bc86d8fe3d",
|
||||
"88ec4ff5a1b0ffdabfe62d068286c851ee64c428883e56f32af14b59756d5846be9d46e5a777c4c22f2dec9596a1a44ed3aa75f1fb0231923cbd4ab59f1f9c47",
|
||||
"892bf89bd3a008a7d982de0d278349e654c713efacf965e88e46a12398375cd8502711378e378c39c33b2f995f47799760c6e6e05948b93c0d2b9fd427854ffc",
|
||||
"894bd433b4b06514195a604961c871649e108d210a41d5cbebe76f78cb6270b7708d1c59d6cb88807f882bb154be1c9058a753e2b6a95c3f4ac9e27a02036f12",
|
||||
"896256329fbeb5b8116349c31d8a39a7d36d5f970d48558e1db5417d611e240e4dbf473f6e49137f7aa6116394b7deabb0bbec4a014896cdc9484ee91458117d",
|
||||
"897c3401b4a35d8fad5966bf8c4dce6d94837c76e46e8131a8bd70527f6e1d8c9f59053d0a56425d7dee71939280ac3c38df14e976f613cb906d7187d6141297",
|
||||
"89e6f6a865ab743936a9b29d53b67bf4b68660ccbe834d4a11fa9011edb535e3b7b4d7a238c84971d4cb5f06ef7398bfecc4f2b786200fee67d7307f242da565",
|
||||
"8b707d4f8f32c80709d880fb257873915033c7d5bce9589a80ca9437618262c55dbe8eec2e8c82469bc335a84a8f16f89afcc53b8329dced5407a513927efc4c",
|
||||
"8e98d00c5d110856943461cd85305b0a817abb457c2afc8e89edb32e502d0060081c8e667d9fceb63a2f8efbcb6e193e9b0231afcc05ecb2303d7f742f304396",
|
||||
"90bb7c91281bb6625a0700c1ee2f3cee488cb9c1864ccf2e24699c5d957b1b7b686574d11acb37572fdf18a15f272fd44009b6cfce9b6cdf9025dd5002869d30",
|
||||
"911c26cf828319df5123a9cf38641704961a6b894aa6ee2b0d13409996a93d89f4868b91e0eb1efea907a70a14cf3a3bd8935033aeb03bd8555f2dea857a48bd",
|
||||
"92862e616dce7469bafc507ab8fbb47bb6f5ca8b96b05e9fbf39a259d1d4c4cac97b0472f713db2e5fbff0d3e587e7b34bedff80cc2a70c446becf9b488370d9",
|
||||
"92a15e2cbd0c89fbce36b05e3b282255097bb5492fc11f0d2b0a08c4311621a41ec35df201de51523b62189a3b44bb3eb1cbdf64e80f4a543d0d9f9a99f9bd3f",
|
||||
"97679def7032179662646816abc12f74fc693fb02c43675a2d5407e58be6dacd1eb483d1bf46f66c5103de3a649211c29e1127dca473e13b02dcd5e7df719cc0",
|
||||
"97e29f9edfe712b059203de5af236569e2c41fae8cddfc7b486204d6e30c411ec605c757fa5a1a151646092bd5d71de18a5f2d8b6fb74b9a28a7c7226a4f641b",
|
||||
"9b5f9ebc961424b8a6b7def59a86ad6fa6e45fc9ad5fb251c15d4d09202e6d3f63bb37b80faa4fdfe3997182079988d78556a9ebf7db535951a1e3cba0c0f6c9",
|
||||
"9b847b5006ea1b47dc0ec366d09aec4a67aec747c55af554c094994fe8c8625b09cfd5322958c816bea74f725abb3d1403f2e9336007db3b257949401b1fef03",
|
||||
"9cdf4ab91c8ef6148dfd724f2a2c644cc00df44f5eea5035e760ac59ec79078ffaf3d97a9c5a9747c04895a3dc666339f82cd17e40095b9fd055df3ff07da6d6",
|
||||
"9fb127fbe4659174b52ef61778a705cc5a96c8f136445bd28c10ac79398ab9ea291852b627e285e828fe37aa23d05b13cf202f3f0cb4c272aba94dd1806802c9",
|
||||
"9fe6ba948da2f4e4aa0e1b0d3e1aec1f093335f8097d7dd3d6b5217cd539f5c41735ef7a615d8210f2e6b777b7198f151264ade172be7dbbf5d442bf91843e8f",
|
||||
"a1afb2eae49546bf59e6f9a1968287add54dd6e336ec795037090a435f736b6d8ba2076e05e27034979a8caaeafce05fc6d9d5541f4e5a4321e64106dabd1549",
|
||||
"a2b06b54679145e65ce10a8356285efcadbacd41be817d2e0858ddba59e638775b79f76cb9e4ac5859627b67ebf227c55b51cc48e6d0d7ef41c9845d96ded68a",
|
||||
"a2b503bc78bd0b68fcdc3e3b68e3c68cf3da8d2d48d91f09313c7cdc11b43dd4d4de3a8a2c4b526809adf9879427c4818db72cffdbc2f0015a9fa5ade83bd400",
|
||||
"a359c15185b6d2a402dacfb7b3dc2e3ce5fd80a1add892b2dcf8e23bebe57f16680eebf7a851c3a870d3ba9932c4e42bad937c4676931d849c62f021ba812860",
|
||||
"a35dea43a67cbd18b705cf2b28114652686eb409c1ae1e56c04256fd902ba9ab52c7343bb8b162522bf3442da42431246644432c70f819ba8617a723abcce836",
|
||||
"a4b1eb406ff2c349437a5634148365fd0eecad5a264036e3af171d0f6769a7129590a0a3e09592038baa8bc1292af2bbdbfb74e3b1a685844e263532a87baef6",
|
||||
"a4b8fa949865e0aa45147a27f0a034a26e34745d624dcf0603dd25fd1ce279eaf2d073a853d67e6432447d5e06708d71a9cddac0d2918876d2d3498af3ae0892",
|
||||
"a6bc3c6beffd4335228c3b4857365215f0c4bc5197a5b0eca95334af33dba19ebf8d513f6c75359d7cb678b051d96579d73ebdaa5b6906e3b6eab35005bee13e",
|
||||
"aabfdbdc21150ac70f9bb1a34f4d7de570a72ba7e1afd8c08d64c85e00c12e6ca1f2ffe60dbd16a871987bd7aa47182baf57e7f68daaf0bac7fc3b907c8ef4c0",
|
||||
"af506d21ee140905c125e61c19d04599354fe84fe211502c9c766951387f6ff79e80db0658392af173f37ef7c92d7815ac9214e8ba4c6ade3e7a7ef014e5cc08",
|
||||
"b04a1d5062f2921f39074e4f5c00675269195834a0a9c0bcce10b1427bf8a6499bdd7d8c6717f220aa4ec9f590bb04b290673018528a60dd819ce9798b0a33b4",
|
||||
"b0a3c5148905a3e7e18c773684026e4ccd8811c3c62f6fcfc23135686a8db9c2caa6de7b14775e29b7cdeb360ae25ea626381c7689ade892c3fb72f82e2daa89",
|
||||
"b1a0cbb91459433ff6de32b189783a734c2ada4c04d7dd164de449ce79c749d382aff10aa9ed7b4449af3390da51585123ef88719ecf7cfea9c24223023a23dd",
|
||||
"b47a96b489f4dd851c364dee278699905f1ed933ba3a98a6660160463a8decef830bb91ac0a1b4f9b742df2dfbdc9625ec27133a69f6cf3cb81ed298183764e7",
|
||||
"b52e493e5049e86223385546f3407f5924fd75311a0a11af38423b7bb7c02c3f085fd1d9188515c7b43c59fbf168c23126456dba98dc9c0d29b7a3edee159015",
|
||||
"b5419f6ea89dc32431a7671df1ebf934647bba5b27db54235fb1e47d691b70c3160bf8019653d5faad616b169adfea5d8e7077e9820d9294144354133d45ee16",
|
||||
"b570d19edbda421e0975056b5fdf4cefbc3825b840aacaa337567ec1aa151a81633eb645a86c8c1c22b23e7f916c60c20cb115de29b670511fb9413611e8cc3b",
|
||||
"baff09432cffceac6ecd395a8ed5c947fdafe6c30c1c0f3b83c4ddfaa2ca9d57b21876153ac2b82067d7d37bc6789e2f68558f1f26fbcd53fd6a500124f80655",
|
||||
"bc0b544f1c13cc1d0fe15b0eab96e89e6d4dfc8919de1fb757ef97a7d5de9efff5e520def5a8471b75480fd49d410d222ed9332089bd527946c74070e8ad1934",
|
||||
"bc3886ba087d3fd637a4fa85adf33170e23b369c0c6eca422ddb26c73c04ae467e2b95ed73bead19013001af65bf2cf0d686a6e702b458a77068184c8b17dfb5",
|
||||
"bd609b6955a6a35a5580a6e19e173b02fa6d4ed880b6cba8fb5d2fd91309dc753326a824a47ee6148b3d6a01b9b49ce7c1122b1e30b6ea181bd257bbc38c2940",
|
||||
"bet",
|
||||
"bf64f21ff129fae4bf3ff795c39df0a4a6dc40ece1d71747a913dd84af2e4cac4e1b84213e23cb1397b3299f26b1b6302a3cdbd41da8baea2505febd6e1803ce",
|
||||
"bfe8d96ce71f9cce7bd16b5282041c66773405f1a11f4f0c8d3b6e81646f262bdac0cb3ee8f54e13175ba9ed7da38407e8a9aeff20972271f0c62c0b19f8b644",
|
||||
"c088e98f02d33581ac0d79c37a101e4273e0750a5691cffd96a09c38742617dae948cbc4affbff4ece1d611e44ea5539f0597eef33ef39f7f0e3ec2a5edf75eb",
|
||||
"c1bafe50eb70a1b65188fac549c6bbe7f641b672fbe9fd08cb64ed1f176efbedeca88f5c295d508e2dbf9b495fe0040bbbfbc4776af0d6cad6576a997db3e4cc",
|
||||
"c1e166044d7731207ce8b838011eae84814857a8ddb63b8a393d2497bdcd7e96d045aa229a7978533646cf9f9ea99a619943599d47a1558073690601fb486ad5",
|
||||
"c21ee36416076c1929dd93af7e936e371d4fe263662a2deb8fd6b0e5cd5b8cd86437b4afb2faa8813bd7b8689c7f56a63729a1e666684d8303f469faad669e54",
|
||||
"c3f1018eb1f7b5e5c0210deab309d06d3e8e9e15ec7dd41d2dbcf863c39e36955b2034fe44af5a4983285b8fc6c0d92b092f95383f8989c1d75a40a4bcdd3d83",
|
||||
"c4d740361d5f6bdcf408abc029d8adceb35f06c332c46fc290d187d96562992a8d6caa562eaa21643c346d44c9e706cd991ba986e53cfe37b41a0e048d14d6e0",
|
||||
"c5d4c712e06053bc35bc6cef173daaaae7fd47db5ac812b95a2f0f08374432ffeaa2b49a0f10cb60f38405d2459489df0e43fb73b48bdb6caadcb4405915c33e",
|
||||
"c777d3358a0aff067b64f254ac462fa223a1650af20ce2af341de610eebbb55a128a1dc43c91da7a1844848b5920b7dd5c5e0a1e8651d6442a2418709dad8c87",
|
||||
"c96c4e97012d25add2fe69513a5b1f941fc36c837737780c443203c72182b808a129982ebd64aaffb8eda4ba3c8787fd98ca55fd33f060f63917567446417574",
|
||||
"c9774fae6c0a30b456a21005abf026799f370a12fbcbc098e81bac2456955320ec6e712f1d6f9d59a50d615f81c6284785292180364598987a7990ae83c0f0c9",
|
||||
"cb557116fa7b3b6da35024b539795d9e255c111c06edbf0e77ba728dd352353182c96918c649fb9327bbb4fea1bb25affcade9b5069676b191611062941356e7",
|
||||
"cc3b30ba0f733abfe64667838f620c4f542db4665fa68e4d945b75ac0d2c435e6529e6541c4ac8ca18dec753b10e3a5c4614cfbc658dc951ab6cab357e6ef363",
|
||||
"ccd85fb40538f948396a4c2bf381ea591927a7cde9330ecab883cad5bd59db56f0c983362f9d0a8e88a67d3f2bae2182bc8ea94b4e3adc721c782ca5c801e2af",
|
||||
"cd1226e73c8275de15f2edb3744a413277fc76a4ebb7842fb743215c14b405b96c4e64bc8324feafe58937da218a1b0aeb9451d5781672ced1ad68c31eb54ba1",
|
||||
"cdc5df38351edbdf7afdb3aaf0b4f53253cedbf3f43d662548a432f86389505fd6f2f64f51f951355f4fcfc5718a98dd782e1472246556c87f0bbaacebb38cb8",
|
||||
"ce31dc5dfa61834e3ab67925ff5f24baf04b4aee6e35cd8ffa524f87b2e2e094999f85c68cc7a1c0e9b19016d050c1755406d02f7116ef85afa355c65a9a5855",
|
||||
"cefa12e7ac99a5d11df487ab6521837b11165246d1c3cdb2108770532cb1429c2dcba5262a4dbd9a37686bb76ad1c48ddecf473d807c2e552534b24bb78ee30d",
|
||||
"cf5b890eb74b4ac647d011a989a92a413c23c0db580c87057fc5afba2d83dd861f2a8640fb952381d090328d6278dbe56713d516020ce95cfb6d4fecf63b89e7",
|
||||
"cf8c583b1282449a97b72e317e56d5a4d1432e5420148a21ba8fd8bb2a172c7832379f30cd6582bd6674b548deb8517c8915c5c4b423bd3e73903f71b8862380",
|
||||
"d0cd44fcdae652efb0dd428cd1b8f1911e6eb2ca3469a1f2d6f9faf97a9d05e30f28387dfb81bfb4c97eba64187a0c047c85bf06998ccaec58781f3982626bb6",
|
||||
"d15bfc3278de168872744ebec8fc7a07678bd04b7557e89749eeedc7087fe0a36cb8b094e978e979d67feba46c4a2741f0fab18010796b5ff436836a5fc67e88",
|
||||
"d3d64ab67746fcb7b4a37d6b6b80c9d4b11afd9e15d81a60b3fde53e4f99267a63b50cfb2184c7c84c9f0dd4345c0d929160a7df52698a82603c112e0bf8ab8e",
|
||||
"d647b73602a3a0c1b06f282a612c29eefc6a7e372bc8af212a41f481843c23a975b41ca402f06ecb7dc660d4dd22a814f7659b48da7dfd28c02a319032394da1",
|
||||
"d98d182c89b465adb0fdd1cc5c2bcb22b81fcc4eb941977b667de22927ccc9a7876033008118957d803c83afb95595986bcc076e77483dd55dca91ce253ba010",
|
||||
"dafd89491990553f5e22021f96344b3bc92be6a419c919ba78860876f226e51e668dbabcb11cf9500f3bd05582b387907ea007b5e8f37c78fb71ac819b9bc20e",
|
||||
"db6932752693a1b2e7ef9af4adbf6fc8a299f21965ff9ff52b141563a471600df9308a89562af7b664b7fe14da134b4f44beafcf910f8794652e16dc475796b5",
|
||||
"db8eecd1ac9b20918e31f04331e46007f367c1f6365c9c4abb7af70eb1d2ea12174375fb95d1d11c46e03c81976de6d68f70693e1ea7f2096aecf06307a17d29",
|
||||
"dbe9efadf636bdd82f3ac2b3710653421e7cefca01b74012824b73f7368469fc4dd7e788b047920d4b3b7e4a486c732872ca11a75a89d1323337191ac2bc899e",
|
||||
"dca1aa77f919ef1000d91291ba68800340332c299e3c4c6bcabb41fd2305f36db353211d6ac691c37d16889e3c3ffc1efb7c621e8040cb77b7249e264af44768",
|
||||
"dee065b956b99b10db4763759d64c41791af1a7e77f1864f90a2b0847a12633dcf9bc108db7eaf73cc8d0e750f5c37383a56cd77cc2276d3960104c6bebe6346",
|
||||
"df52eb2c24a6c35b977a1d0fab336ab5c21cd84f78f685d5f0bea9ebaa7c078c0ca69717455e29f17bcd9282a1af9cbbe2d3e608c62cecf868419da081e2d810",
|
||||
"dfc8721858bd56b846473eb6123420a2735fc69cd77a92a1d2c623c51eab3ac664d61a890d305c6fe77ec48f2759248744e9d56689f6c22317bbaa316c848fbc",
|
||||
"e249989b0c397ac03583594a3911c9e9222ccce620921170bb39b8ab6fdaf136b164f3c9fcd8b4f750fc469c9cd69f144c2ca2dd918fcb778148fbf9751a869b",
|
||||
"e364856fe22a5c80cc8d13ee445473a0eb7204bad6972fc4c116ea1551b50da43a01577ef0487f2afb7aaee4b4155d61b1ff2b83dc502363929de76af0226818",
|
||||
"e37d85b60af58cc03e9b36e09dee5e8308368f44f91b28455e7f645a13fe29902e7f7d594ccb600e02caf4202a05d15477d4ea5191c7b97038ea06d73ce93c33",
|
||||
"e41b679ec1446821bf0a80fa7003fb90ac66b79d09c00dccf702a1b254f9ea85a68b0643ecd81d999413d5814b06b9998afd9876062067f51a63747533921d08",
|
||||
"e61565e75d632748413d51997cabb00613355f0a94cf6b2f929fdfa351490d2afc9bad72c7fa67595d9d9c7adc9454e8d1b05527991a17258424b14ec4e9a1d5",
|
||||
"e6a64aa839b95caeb74d810677a33b747e23907213719dd9706af7364b4cacf204b09f9b26686a70cd6d416a6b590f87103cc683685529968ea0edd75107f649",
|
||||
"e751d2f83310990aedc7392b54f827afac1873e9f8861e625814a8d1d15776160864742d557796d07a612479b2886287b417273cc9f7718889216c2ec3b3b7ed",
|
||||
"e7847a5814b865bc043600fee7d810b9815da389278fdfdd412114ab8f87b1536f4b63f3f7c3d3eeb097486abc152043eefdae6fd12c2f8743dac1cb668ab136",
|
||||
"e82ba384934ac4780595261c43eeceb3df29a047087870f5da13c7acae782b4b97857b98852ce235428b4bc24aa4ddcdcd7297acf683421201eff1c3fbcab84e",
|
||||
"e9da05b6d590dcf94addabd168c543be41a2275ddf44f6f44db1e3698f0bf7dd67f2e93b66679e0a0d42a2f39f3bc6a389f0e6b362431d0cb197fe46f9dd6606",
|
||||
"ea8456e0667e1cce6273cb333b7e6982f9aa0f260c7c103e04eb0076a73fe3497070b1a8f0c45b097dc3100a30254095a1c63e9514367655e9a378344ed25d1d",
|
||||
"eb415e110eaff48bdbc03b5ab719f64593f222b4a1d872b552e4fc48d338e532d1954f76e94813e44a6cd030425b4076cd7b9bf388b870a31344545d092dfa1a",
|
||||
"eb5078bcb64f9595d6d8589ad60502b2870f16942fbb4cbd2483c817c7fa460faeda90b82bcf531ac96be8c1d6825953ab85ab0bd46ea477615e71e50386ffe0",
|
||||
"ed5c9e654bfb28e9d4131b3805597ee9fa14fe72c6e2a6d503ec2e47faf396bbfa15ce49e6fe83bd97da1d441138545d388a329ae888c1f1ea44fc62996d787f",
|
||||
"edba91511ccf8ab01de2e2cef34c47d8430f8a2f4c62cd66c42ecb62da52d396e909aef7da067eedc58e1eb58a1fc3697939371e6a36c931af5987a50509854b",
|
||||
"ee216d2d13cba1a951445b061771ab0c97eb3c250003e16008debd85fa0317a508f923db79c796dc29de18c83baad5b15651f80db1cf7aee854e6da28853b742",
|
||||
"eli",
|
||||
"eva",
|
||||
"f1812dbb566edaa2ac92121641e5ae504d647bec835a02ed5d7c7f90424d0e8fe202846a599c2f74c49ec9b86181d3d6c50ac0688baa9b4c28608d592becdfdb",
|
||||
"f26a63e5171e2935e13015fbb755f04bff87fb1767ac91aa3481b9fe13b54cc75f772b41dfdc634829dd9b44c7b08798ed114046ef981d454889c41d4f6408d9",
|
||||
"f2f359ea473c07070fd1e50d2fcfe3dc4f624f01678c35920b079660b2d5b9c1743259ae6129992cd3b99ec2cdda94a45e8710888488b196c6cd9c853e86e454",
|
||||
"f35ce011f75fc01d153a94339aad24ae4fd5f181af55916a5ca0153cd5220ed199b98459eb88e9f4f3a4f8fbcf5c272bafdca35ddaca0827c4b480f79e7db1d6",
|
||||
"f4df4a067fec667827901fb55acb16acc4650f24eeaa588af1a103e5009e9166f753c7cd313d0d3dec79abb82a13c43fd2059db5ac0307b78369ca318001c4e7",
|
||||
"f56a47b89ebd2d22f869e2260b55f70d7ae0d499fc3fd4dbcb0e6e507f12513f29c004b9426e428696df0d434e4ad467f143bc620a2f661a54608de9e2c265d5",
|
||||
"f61bdd3abb2d03f07e33bfb0b9fba46069468cefd9eda04e77cdc5c2f13a417716d3e60ca91c39de1a480b72112ef0e6143e927fad45410ee252cfce9034f0b1",
|
||||
"f62196a11f50362b35eb1ed830b03c18bb187e4d07014a3d1b238756fe836f254afa923184170512a0c6d990032b4b1edb25dd2b74f6fc15f6ef6b51b6f82dd4",
|
||||
"f8e4bf2dd4f93dd473b055ebf2dfa6081703014fddca40a0efb6bd5dcb702244a30a2d3edcd6597ea4118c20258da575a0bc69a895356519d8400a5ad3b2bf58",
|
||||
"f980d152d5c14c6e7557f13fe26305ed0105dbb23177d455372e5529a5d3333e203070e87352d985a136f5ce3976a16b97070a4343fb4cb9d0760d9bcd5c7677",
|
||||
"fa8641fb64db60e7299f070f6497678dee0bfdeefcc22a51ca328da34b33fdd6c31b882d97fc32cfcdeee4fcb72b05d7eae43b10b531db161b7e8dcfc2775ebf",
|
||||
"fdde8cdd2fa5689aec75121e3c0778ca8c37238fd6a64706d85a4156d7735c482f1db74cefd023e94587b64a56d4a06e3b7fecf5c85978a4c777c9eaa5c633fd",
|
||||
"jan",
|
||||
"mar",
|
||||
"ona",
|
||||
"pau",
|
||||
"pep",
|
||||
"pol",
|
||||
"teo"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"fa": {
|
||||
"custom": {
|
||||
"glow-tts": {
|
||||
"id": "tts_models/fa/custom/glow-tts"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bn": {
|
||||
"custom": {
|
||||
"vits-male": {
|
||||
"id": "tts_models/bn/custom/vits-male"
|
||||
},
|
||||
"vits-female": {
|
||||
"id": "tts_models/bn/custom/vits-female"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -651,6 +651,7 @@ function onTtsProviderSettingsInput() {
|
||||
ttsProvider.onSettingsChange()
|
||||
|
||||
// Persist changes to SillyTavern tts extension settings
|
||||
|
||||
extension_settings.tts[ttsProviderName] = ttsProvider.settings
|
||||
saveSettingsDebounced()
|
||||
console.info(`Saved settings ${ttsProviderName} ${JSON.stringify(ttsProvider.settings)}`)
|
||||
|
@ -4,7 +4,8 @@
|
||||
"requires": [],
|
||||
"optional": [
|
||||
"silero-tts",
|
||||
"edge-tts"
|
||||
"edge-tts",
|
||||
"coqui-tts"
|
||||
],
|
||||
"js": "index.js",
|
||||
"css": "style.css",
|
||||
|
129
public/scripts/filters.js
Normal file
129
public/scripts/filters.js
Normal file
@ -0,0 +1,129 @@
|
||||
import { fuzzySearchCharacters, fuzzySearchGroups, power_user } from "./power-user.js";
|
||||
import { tag_map } from "./tags.js";
|
||||
|
||||
export const FILTER_TYPES = {
|
||||
SEARCH: 'search',
|
||||
TAG: 'tag',
|
||||
FAV: 'fav',
|
||||
GROUP: 'group',
|
||||
};
|
||||
|
||||
export class FilterHelper {
|
||||
constructor(onDataChanged) {
|
||||
this.onDataChanged = onDataChanged;
|
||||
}
|
||||
|
||||
filterFunctions = {
|
||||
[FILTER_TYPES.SEARCH]: this.searchFilter.bind(this),
|
||||
[FILTER_TYPES.GROUP]: this.groupFilter.bind(this),
|
||||
[FILTER_TYPES.FAV]: this.favFilter.bind(this),
|
||||
[FILTER_TYPES.TAG]: this.tagFilter.bind(this),
|
||||
}
|
||||
|
||||
filterData = {
|
||||
[FILTER_TYPES.SEARCH]: '',
|
||||
[FILTER_TYPES.GROUP]: false,
|
||||
[FILTER_TYPES.FAV]: false,
|
||||
[FILTER_TYPES.TAG]: { excluded: [], selected: [] },
|
||||
}
|
||||
|
||||
tagFilter(data) {
|
||||
const TAG_LOGIC_AND = true; // switch to false to use OR logic for combining tags
|
||||
const { selected, excluded } = this.filterData[FILTER_TYPES.TAG];
|
||||
|
||||
if (!selected.length && !excluded.length) {
|
||||
return data;
|
||||
}
|
||||
|
||||
function isElementTagged(entity, tagId) {
|
||||
const isCharacter = entity.type === 'character';
|
||||
const lookupValue = isCharacter ? entity.item.avatar : String(entity.id);
|
||||
const isTagged = Array.isArray(tag_map[lookupValue]) && tag_map[lookupValue].includes(tagId);
|
||||
return isTagged;
|
||||
}
|
||||
|
||||
function getIsTagged(entity) {
|
||||
const tagFlags = selected.map(tagId => isElementTagged(entity, tagId));
|
||||
const trueFlags = tagFlags.filter(x => x);
|
||||
const isTagged = TAG_LOGIC_AND ? tagFlags.length === trueFlags.length : trueFlags.length > 0;
|
||||
|
||||
const excludedTagFlags = excluded.map(tagId => isElementTagged(entity, tagId));
|
||||
const isExcluded = excludedTagFlags.includes(true);
|
||||
|
||||
if (isExcluded) {
|
||||
return false;
|
||||
} else if (selected.length > 0 && !isTagged) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return data.filter(entity => getIsTagged(entity));
|
||||
}
|
||||
|
||||
favFilter(data) {
|
||||
if (!this.filterData[FILTER_TYPES.FAV]) {
|
||||
return data;
|
||||
}
|
||||
|
||||
return data.filter(entity => entity.item.fav || entity.item.fav == "true");
|
||||
}
|
||||
|
||||
groupFilter(data) {
|
||||
if (!this.filterData[FILTER_TYPES.GROUP]) {
|
||||
return data;
|
||||
}
|
||||
|
||||
return data.filter(entity => entity.type === 'group');
|
||||
}
|
||||
|
||||
searchFilter(data) {
|
||||
if (!this.filterData[FILTER_TYPES.SEARCH]) {
|
||||
return data;
|
||||
}
|
||||
|
||||
const searchValue = this.filterData[FILTER_TYPES.SEARCH].trim().toLowerCase();
|
||||
const fuzzySearchCharactersResults = power_user.fuzzy_search ? fuzzySearchCharacters(searchValue) : [];
|
||||
const fuzzySearchGroupsResults = power_user.fuzzy_search ? fuzzySearchGroups(searchValue) : [];
|
||||
|
||||
function getIsValidSearch(entity) {
|
||||
const isGroup = entity.type === 'group';
|
||||
const isCharacter = entity.type === 'character';
|
||||
|
||||
if (power_user.fuzzy_search) {
|
||||
if (isCharacter) {
|
||||
return fuzzySearchCharactersResults.includes(parseInt(entity.id));
|
||||
} else if (isGroup) {
|
||||
return fuzzySearchGroupsResults.includes(String(entity.id));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return entity.item?.name?.toLowerCase()?.includes(searchValue) || false;
|
||||
}
|
||||
}
|
||||
|
||||
return data.filter(entity => getIsValidSearch(entity));
|
||||
}
|
||||
|
||||
setFilterData(filterType, data) {
|
||||
const oldData = this.filterData[filterType];
|
||||
this.filterData[filterType] = data;
|
||||
|
||||
// only trigger a data change if the data actually changed
|
||||
if (JSON.stringify(oldData) !== JSON.stringify(data)) {
|
||||
this.onDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
getFilterData(filterType) {
|
||||
return this.filterData[filterType];
|
||||
}
|
||||
|
||||
applyFilters(data) {
|
||||
return Object.values(this.filterFunctions)
|
||||
.reduce((data, fn) => fn(data), data);
|
||||
}
|
||||
}
|
@ -7,8 +7,8 @@ import {
|
||||
createThumbnail,
|
||||
extractAllWords,
|
||||
} from './utils.js';
|
||||
import { RA_CountCharTokens, humanizedDateTime, dragElement } from "./RossAscends-mods.js";
|
||||
import { sortCharactersList, sortGroupMembers, loadMovingUIState } from './power-user.js';
|
||||
import { RA_CountCharTokens, humanizedDateTime, dragElement, favsToHotswap } from "./RossAscends-mods.js";
|
||||
import { loadMovingUIState, sortEntitiesList } from './power-user.js';
|
||||
|
||||
import {
|
||||
chat,
|
||||
@ -61,8 +61,10 @@ import {
|
||||
getCurrentChatId,
|
||||
setScenarioOverride,
|
||||
getCropPopup,
|
||||
system_avatar,
|
||||
} from "../script.js";
|
||||
import { appendTagToList, createTagMapFromList, getTagsList, applyTagsOnCharacterSelect, tag_map } from './tags.js';
|
||||
import { FilterHelper } from './filters.js';
|
||||
|
||||
export {
|
||||
selected_group,
|
||||
@ -75,7 +77,6 @@ export {
|
||||
deleteGroup,
|
||||
getGroupAvatar,
|
||||
getGroups,
|
||||
printGroups,
|
||||
regenerateGroup,
|
||||
resetSelectedGroup,
|
||||
select_group_chats,
|
||||
@ -87,15 +88,17 @@ let groups = [];
|
||||
let selected_group = null;
|
||||
let group_generation_id = null;
|
||||
let fav_grp_checked = false;
|
||||
let fav_filter_on = false;
|
||||
let openGroupId = null;
|
||||
let newGroupMembers = [];
|
||||
|
||||
export const group_activation_strategy = {
|
||||
NATURAL: 0,
|
||||
LIST: 1,
|
||||
};
|
||||
|
||||
export const groupCandidatesFilter = new FilterHelper(debounce(printGroupCandidates, 100));
|
||||
const groupAutoModeInterval = setInterval(groupChatAutoModeWorker, 5000);
|
||||
const saveGroupDebounced = debounce(async (group) => await _save(group), 500);
|
||||
const saveGroupDebounced = debounce(async (group, reload) => await _save(group, reload), 500);
|
||||
|
||||
async function _save(group, reload = true) {
|
||||
await fetch("/editgroup", {
|
||||
@ -226,9 +229,8 @@ async function saveGroupChat(groupId, shouldSaveGroup) {
|
||||
});
|
||||
|
||||
if (shouldSaveGroup && response.ok) {
|
||||
await editGroup(groupId);
|
||||
await editGroup(groupId, false, false);
|
||||
}
|
||||
sortCharactersList();
|
||||
}
|
||||
|
||||
export async function renameGroupMember(oldAvatar, newAvatar, newName) {
|
||||
@ -245,7 +247,7 @@ export async function renameGroupMember(oldAvatar, newAvatar, newName) {
|
||||
|
||||
// Replace group member avatar id and save the changes
|
||||
group.members[memberIndex] = newAvatar;
|
||||
await editGroup(group.id, true);
|
||||
await editGroup(group.id, true, false);
|
||||
console.log(`Renamed character ${newName} in group: ${group.name}`)
|
||||
|
||||
// Load all chats from this group
|
||||
@ -330,8 +332,7 @@ async function getGroups() {
|
||||
}
|
||||
}
|
||||
|
||||
function printGroups() {
|
||||
for (let group of groups) {
|
||||
export function getGroupBlock(group) {
|
||||
const template = $("#group_list_template .group_select").clone();
|
||||
template.data("id", group.id);
|
||||
template.attr("grid", group.id);
|
||||
@ -345,17 +346,20 @@ function printGroups() {
|
||||
const tagsElement = template.find('.tags');
|
||||
tags.forEach(tag => appendTagToList(tagsElement, tag, {}));
|
||||
|
||||
$("#rm_print_characters_block").prepend(template);
|
||||
updateGroupAvatar(group);
|
||||
}
|
||||
const avatar = getGroupAvatar(group);
|
||||
if (avatar) {
|
||||
$(template).find(".avatar").replaceWith(avatar);
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
function updateGroupAvatar(group) {
|
||||
$("#rm_print_characters_block .group_select").each(function () {
|
||||
$("#group_avatar_preview").empty().append(getGroupAvatar(group));
|
||||
|
||||
$(".group_select").each(function () {
|
||||
if ($(this).data("id") == group.id) {
|
||||
const avatar = getGroupAvatar(group);
|
||||
if (avatar) {
|
||||
$(this).find(".avatar").replaceWith(avatar);
|
||||
}
|
||||
$(this).find(".avatar").replaceWith(getGroupAvatar(group));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -397,7 +401,7 @@ function getGroupAvatar(group) {
|
||||
|
||||
// default avatar
|
||||
const groupAvatar = $("#group_avatars_template .collage_1").clone();
|
||||
groupAvatar.find(".img_1").attr("src", group.avatar_url);
|
||||
groupAvatar.find(".img_1").attr("src", group.avatar_url || system_avatar);
|
||||
return groupAvatar;
|
||||
}
|
||||
|
||||
@ -783,8 +787,6 @@ function activateNaturalOrder(members, input, lastMessage, allowSelfResponses, i
|
||||
return memberIds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function deleteGroup(id) {
|
||||
const response = await fetch("/deletegroup", {
|
||||
method: "POST",
|
||||
@ -823,7 +825,7 @@ export async function editGroup(id, immediately, reload = true) {
|
||||
return await _save(group, reload);
|
||||
}
|
||||
|
||||
saveGroupDebounced(group);
|
||||
saveGroupDebounced(group, reload);
|
||||
}
|
||||
|
||||
let groupAutoModeAbortController = null;
|
||||
@ -849,104 +851,223 @@ async function groupChatAutoModeWorker() {
|
||||
|
||||
async function modifyGroupMember(chat_id, groupMember, isDelete) {
|
||||
const id = groupMember.data("id");
|
||||
|
||||
const template = groupMember.clone();
|
||||
let _thisGroup = groups.find((x) => x.id == chat_id);
|
||||
template.data("id", id);
|
||||
const thisGroup = groups.find((x) => x.id == chat_id);
|
||||
const membersArray = thisGroup?.members ?? newGroupMembers;
|
||||
|
||||
if (isDelete) {
|
||||
$("#rm_group_add_members").prepend(template);
|
||||
} else {
|
||||
$("#rm_group_members").prepend(template);
|
||||
}
|
||||
|
||||
if (_thisGroup) {
|
||||
if (isDelete) {
|
||||
const index = _thisGroup.members.findIndex((x) => x === id);
|
||||
if (index !== -1) {
|
||||
_thisGroup.members.splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
_thisGroup.members.push(id);
|
||||
template.css({ 'order': _thisGroup.members.length });
|
||||
const index = membersArray.findIndex((x) => x === id);
|
||||
if (index !== -1) {
|
||||
membersArray.splice(membersArray.indexOf(id), 1);
|
||||
}
|
||||
await editGroup(selected_group);
|
||||
updateGroupAvatar(_thisGroup);
|
||||
}
|
||||
else {
|
||||
template.css({ 'order': 'unset' });
|
||||
} else {
|
||||
membersArray.unshift(id);
|
||||
}
|
||||
|
||||
groupMember.remove();
|
||||
const groupHasMembers = !!$("#rm_group_members").children().length;
|
||||
if (openGroupId) {
|
||||
await editGroup(openGroupId, false, false);
|
||||
updateGroupAvatar(thisGroup);
|
||||
}
|
||||
|
||||
printGroupCandidates();
|
||||
printGroupMembers();
|
||||
|
||||
const groupHasMembers = getGroupCharacters({ doFilter: false, onlyMembers: true }).length > 0;
|
||||
$("#rm_group_submit").prop("disabled", !groupHasMembers);
|
||||
}
|
||||
|
||||
async function reorderGroupMember(chat_id, groupMember, direction) {
|
||||
const id = groupMember.data("id");
|
||||
const group = groups.find((x) => x.id == chat_id);
|
||||
const thisGroup = groups.find((x) => x.id == chat_id);
|
||||
const memberArray = thisGroup?.members ?? newGroupMembers;
|
||||
|
||||
const indexOf = memberArray.indexOf(id);
|
||||
if (direction == 'down') {
|
||||
const next = memberArray[indexOf + 1];
|
||||
if (next) {
|
||||
memberArray[indexOf + 1] = memberArray[indexOf];
|
||||
memberArray[indexOf] = next;
|
||||
}
|
||||
}
|
||||
if (direction == 'up') {
|
||||
const prev = memberArray[indexOf - 1];
|
||||
if (prev) {
|
||||
memberArray[indexOf - 1] = memberArray[indexOf];
|
||||
memberArray[indexOf] = prev;
|
||||
}
|
||||
}
|
||||
|
||||
printGroupMembers();
|
||||
|
||||
// Existing groups need to modify members list
|
||||
if (group && group.members.length > 1) {
|
||||
const indexOf = group.members.indexOf(id);
|
||||
if (direction == 'down') {
|
||||
const next = group.members[indexOf + 1];
|
||||
if (next) {
|
||||
group.members[indexOf + 1] = group.members[indexOf];
|
||||
group.members[indexOf] = next;
|
||||
}
|
||||
}
|
||||
if (direction == 'up') {
|
||||
const prev = group.members[indexOf - 1];
|
||||
if (prev) {
|
||||
group.members[indexOf - 1] = group.members[indexOf];
|
||||
group.members[indexOf] = prev;
|
||||
}
|
||||
}
|
||||
|
||||
await editGroup(chat_id);
|
||||
updateGroupAvatar(group);
|
||||
// stupid but lifts the manual reordering
|
||||
select_group_chats(chat_id, true);
|
||||
if (openGroupId) {
|
||||
await editGroup(chat_id, false, false);
|
||||
updateGroupAvatar(thisGroup);
|
||||
}
|
||||
// New groups just can't be DOM-ordered
|
||||
else {
|
||||
if (direction == 'down') {
|
||||
groupMember.insertAfter(groupMember.next());
|
||||
}
|
||||
if (direction == 'up') {
|
||||
groupMember.insertBefore(groupMember.prev());
|
||||
}
|
||||
}
|
||||
|
||||
async function onGroupActivationStrategyInput(e) {
|
||||
if (openGroupId) {
|
||||
let _thisGroup = groups.find((x) => x.id == openGroupId);
|
||||
_thisGroup.activation_strategy = Number(e.target.value);
|
||||
await editGroup(openGroupId, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
async function onGroupNameInput() {
|
||||
if (openGroupId) {
|
||||
let _thisGroup = groups.find((x) => x.id == openGroupId);
|
||||
_thisGroup.name = $(this).val();
|
||||
$("#rm_button_selected_ch").children("h2").text(_thisGroup.name);
|
||||
await editGroup(openGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
function isGroupMember(group, avatarId) {
|
||||
if (group && Array.isArray(group.members)) {
|
||||
return group.members.includes(avatarId);
|
||||
} else {
|
||||
return newGroupMembers.includes(avatarId);
|
||||
}
|
||||
}
|
||||
|
||||
function getGroupCharacters({ doFilter, onlyMembers } = {}) {
|
||||
function sortMembersFn(a, b) {
|
||||
const membersArray = thisGroup?.members ?? newGroupMembers;
|
||||
const aIndex = membersArray.indexOf(a.item.avatar);
|
||||
const bIndex = membersArray.indexOf(b.item.avatar);
|
||||
return aIndex - bIndex;
|
||||
}
|
||||
|
||||
const thisGroup = openGroupId && groups.find((x) => x.id == openGroupId);
|
||||
let candidates = characters
|
||||
.filter((x) => isGroupMember(thisGroup, x.avatar) == onlyMembers)
|
||||
.map((x, index) => ({ item: x, id: index, type: 'character' }));
|
||||
|
||||
if (onlyMembers) {
|
||||
candidates.sort(sortMembersFn);
|
||||
} else {
|
||||
sortEntitiesList(candidates);
|
||||
}
|
||||
|
||||
if (doFilter) {
|
||||
candidates = groupCandidatesFilter.applyFilters(candidates);
|
||||
}
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
function printGroupCandidates() {
|
||||
$("#rm_group_add_members_pagination").pagination({
|
||||
dataSource: getGroupCharacters({ doFilter: true, onlyMembers: false }),
|
||||
pageSize: 5,
|
||||
pageRange: 1,
|
||||
position: 'top',
|
||||
showPageNumbers: false,
|
||||
showSizeChanger: false,
|
||||
prevText: '<',
|
||||
nextText: '>',
|
||||
showNavigator: true,
|
||||
callback: function (data) {
|
||||
$("#rm_group_add_members").empty();
|
||||
for (const i of data) {
|
||||
$("#rm_group_add_members").append(getGroupCharacterBlock(i.item));
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function printGroupMembers() {
|
||||
$("#rm_group_members_pagination").pagination({
|
||||
dataSource: getGroupCharacters({ doFilter: false, onlyMembers: true }),
|
||||
pageSize: 5,
|
||||
pageRange: 1,
|
||||
position: 'top',
|
||||
showPageNumbers: false,
|
||||
showSizeChanger: false,
|
||||
prevText: '<',
|
||||
nextText: '>',
|
||||
showNavigator: true,
|
||||
callback: function (data) {
|
||||
$("#rm_group_members").empty();
|
||||
for (const i of data) {
|
||||
$("#rm_group_members").append(getGroupCharacterBlock(i.item));
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function getGroupCharacterBlock(character) {
|
||||
const avatar = getThumbnailUrl('avatar', character.avatar);
|
||||
const template = $("#group_member_template .group_member").clone();
|
||||
const isFav = character.fav || character.fav == 'true';
|
||||
template.data("id", character.avatar);
|
||||
template.find(".avatar img").attr({ "src": avatar, "title": character.avatar });
|
||||
template.find(".ch_name").text(character.name);
|
||||
template.attr("chid", characters.indexOf(character));
|
||||
template.find('.ch_fav').val(isFav);
|
||||
template.toggleClass('is_fav', isFav);
|
||||
template.toggleClass('disabled', isGroupMemberDisabled(character.avatar));
|
||||
|
||||
// Display inline tags
|
||||
const tags = getTagsList(character.avatar);
|
||||
const tagsElement = template.find('.tags');
|
||||
tags.forEach(tag => appendTagToList(tagsElement, tag, {}));
|
||||
|
||||
if (!openGroupId) {
|
||||
template.find('[data-action="speak"]').hide();
|
||||
template.find('[data-action="enable"]').hide();
|
||||
template.find('[data-action="disable"]').hide();
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
function isGroupMemberDisabled(avatarId) {
|
||||
const thisGroup = openGroupId && groups.find((x) => x.id == openGroupId);
|
||||
return Boolean(thisGroup && thisGroup.disabled_members.includes(avatarId));
|
||||
}
|
||||
|
||||
function onDeleteGroupClick() {
|
||||
if (is_group_generating) {
|
||||
toastr.warning('Not so fast! Wait for the characters to stop typing before deleting the group.');
|
||||
return;
|
||||
}
|
||||
|
||||
$("#dialogue_popup").data("group_id", openGroupId);
|
||||
callPopup('<h3>Delete the group?</h3><p>This will also delete all your chats with that group. If you want to delete a single conversation, select a "View past chats" option in the lower left menu.</p>', "del_group");
|
||||
}
|
||||
|
||||
async function onFavoriteGroupClick() {
|
||||
updateFavButtonState(!fav_grp_checked);
|
||||
if (openGroupId) {
|
||||
let _thisGroup = groups.find((x) => x.id == openGroupId);
|
||||
_thisGroup.fav = fav_grp_checked;
|
||||
await editGroup(openGroupId, false, false);
|
||||
favsToHotswap();
|
||||
}
|
||||
}
|
||||
|
||||
async function onGroupSelfResponsesClick() {
|
||||
if (openGroupId) {
|
||||
let _thisGroup = groups.find((x) => x.id == openGroupId);
|
||||
const value = $(this).prop("checked");
|
||||
_thisGroup.allow_self_responses = value;
|
||||
await editGroup(openGroupId, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
function select_group_chats(groupId, skipAnimation) {
|
||||
const group = groupId && groups.find((x) => x.id == groupId);
|
||||
openGroupId = groupId;
|
||||
newGroupMembers = [];
|
||||
const group = openGroupId && groups.find((x) => x.id == openGroupId);
|
||||
const groupName = group?.name ?? "";
|
||||
const replyStrategy = Number(group?.activation_strategy ?? group_activation_strategy.NATURAL);
|
||||
|
||||
setMenuType(!!group ? 'group_edit' : 'group_create');
|
||||
$("#group_avatar_preview").empty().append(getGroupAvatar(group));
|
||||
$("#rm_group_restore_avatar").toggle(!!group && isDataURL(group.avatar_url));
|
||||
$("#rm_group_chat_name").val(groupName);
|
||||
$("#rm_group_chat_name").off();
|
||||
$("#rm_group_chat_name").on("input", async function () {
|
||||
if (groupId) {
|
||||
let _thisGroup = groups.find((x) => x.id == groupId);
|
||||
_thisGroup.name = $(this).val();
|
||||
$("#rm_button_selected_ch").children("h2").text(_thisGroup.name);
|
||||
await editGroup(groupId);
|
||||
}
|
||||
});
|
||||
$("#rm_group_filter").val("").trigger("input");
|
||||
|
||||
$('input[name="rm_group_activation_strategy"]').off();
|
||||
$('input[name="rm_group_activation_strategy"]').on("input", async function (e) {
|
||||
if (groupId) {
|
||||
let _thisGroup = groups.find((x) => x.id == groupId);
|
||||
_thisGroup.activation_strategy = Number(e.target.value);
|
||||
await editGroup(groupId);
|
||||
}
|
||||
});
|
||||
const replyStrategy = Number(group?.activation_strategy ?? group_activation_strategy.NATURAL);
|
||||
$(`input[name="rm_group_activation_strategy"][value="${replyStrategy}"]`).prop('checked', true);
|
||||
|
||||
if (!skipAnimation) {
|
||||
@ -954,53 +1075,15 @@ function select_group_chats(groupId, skipAnimation) {
|
||||
}
|
||||
|
||||
// render characters list
|
||||
$("#rm_group_add_members").empty();
|
||||
$("#rm_group_members").empty();
|
||||
for (let character of characters) {
|
||||
const avatar =
|
||||
character.avatar != "none"
|
||||
? getThumbnailUrl('avatar', character.avatar)
|
||||
: default_avatar;
|
||||
const template = $("#group_member_template .group_member").clone();
|
||||
const isFav = character.fav || character.fav == 'true';
|
||||
template.data("id", character.avatar);
|
||||
template.find(".avatar img").attr("src", avatar);
|
||||
template.find(".avatar img").attr("title", character.avatar);
|
||||
template.find(".ch_name").text(character.name);
|
||||
template.attr("chid", characters.indexOf(character));
|
||||
template.find('.ch_fav').val(isFav);
|
||||
template.toggleClass('is_fav', isFav);
|
||||
|
||||
// Display inline tags
|
||||
const tags = getTagsList(character.avatar);
|
||||
const tagsElement = template.find('.tags');
|
||||
tags.forEach(tag => appendTagToList(tagsElement, tag, {}));
|
||||
|
||||
if (!group) {
|
||||
template.find('[data-action="speak"]').hide();
|
||||
}
|
||||
|
||||
if (
|
||||
group &&
|
||||
Array.isArray(group.members) &&
|
||||
group.members.includes(character.avatar)
|
||||
) {
|
||||
template.css({ 'order': group.members.indexOf(character.avatar) });
|
||||
template.toggleClass('disabled', group.disabled_members.includes(character.avatar));
|
||||
$("#rm_group_members").append(template);
|
||||
} else {
|
||||
$("#rm_group_add_members").append(template);
|
||||
}
|
||||
}
|
||||
|
||||
sortGroupMembers("#rm_group_add_members .group_member");
|
||||
printGroupCandidates();
|
||||
printGroupMembers();
|
||||
|
||||
const groupHasMembers = !!$("#rm_group_members").children().length;
|
||||
$("#rm_group_submit").prop("disabled", !groupHasMembers);
|
||||
$("#rm_group_allow_self_responses").prop("checked", group && group.allow_self_responses);
|
||||
|
||||
// bottom buttons
|
||||
if (groupId) {
|
||||
if (openGroupId) {
|
||||
$("#rm_group_submit").hide();
|
||||
$("#rm_group_delete").show();
|
||||
$("#rm_group_scenario").show();
|
||||
@ -1013,39 +1096,8 @@ function select_group_chats(groupId, skipAnimation) {
|
||||
$("#rm_group_scenario").hide();
|
||||
}
|
||||
|
||||
$("#rm_group_delete").off();
|
||||
$("#rm_group_delete").on("click", function () {
|
||||
if (is_group_generating) {
|
||||
toastr.warning('Not so fast! Wait for the characters to stop typing before deleting the group.');
|
||||
return;
|
||||
}
|
||||
|
||||
$("#dialogue_popup").data("group_id", groupId);
|
||||
callPopup('<h3>Delete the group?</h3><p>This will also delete all your chats with that group. If you want to delete a single conversation, select a "View past chats" option in the lower left menu.</p>', "del_group");
|
||||
});
|
||||
|
||||
updateFavButtonState(group?.fav ?? false);
|
||||
|
||||
$("#group_favorite_button").off('click');
|
||||
$("#group_favorite_button").on('click', async function () {
|
||||
updateFavButtonState(!fav_grp_checked);
|
||||
if (group) {
|
||||
let _thisGroup = groups.find((x) => x.id == groupId);
|
||||
_thisGroup.fav = fav_grp_checked;
|
||||
await editGroup(groupId);
|
||||
}
|
||||
});
|
||||
|
||||
$("#rm_group_allow_self_responses").off();
|
||||
$("#rm_group_allow_self_responses").on("input", async function () {
|
||||
if (group) {
|
||||
let _thisGroup = groups.find((x) => x.id == groupId);
|
||||
const value = $(this).prop("checked");
|
||||
_thisGroup.allow_self_responses = value;
|
||||
await editGroup(groupId);
|
||||
}
|
||||
});
|
||||
|
||||
// top bar
|
||||
if (group) {
|
||||
$("#rm_group_automode_label").show();
|
||||
@ -1056,118 +1108,112 @@ function select_group_chats(groupId, skipAnimation) {
|
||||
$("#rm_group_automode_label").hide();
|
||||
}
|
||||
|
||||
$("#group_avatar_button").off('input').on("input", uploadGroupAvatar);
|
||||
$("#rm_group_restore_avatar").off('click').on("click", restoreGroupAvatar);
|
||||
eventSource.emit('groupSelected', {detail: {id: openGroupId, group: group}});
|
||||
}
|
||||
|
||||
async function uploadGroupAvatar(event) {
|
||||
const file = event.target.files[0];
|
||||
|
||||
async function uploadGroupAvatar(event) {
|
||||
const file = event.target.files[0];
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
const e = await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = resolve;
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
|
||||
|
||||
const croppedImage = await callPopup(getCropPopup(e.target.result), 'avatarToCrop');
|
||||
|
||||
if (!croppedImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const thumbnail = await createThumbnail(croppedImage, 96, 144);
|
||||
|
||||
if (!groupId) {
|
||||
$('#group_avatar_preview img').attr('src', thumbnail);
|
||||
$('#rm_group_restore_avatar').show();
|
||||
return;
|
||||
}
|
||||
|
||||
let _thisGroup = groups.find((x) => x.id == groupId);
|
||||
_thisGroup.avatar_url = thumbnail;
|
||||
$("#group_avatar_preview").empty().append(getGroupAvatar(_thisGroup));
|
||||
$("#rm_group_restore_avatar").show();
|
||||
await editGroup(groupId, true, true);
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
async function restoreGroupAvatar() {
|
||||
const confirm = await callPopup('<h3>Are you sure you want to restore the group avatar?</h3> Your custom image will be deleted, and a collage will be used instead.', 'confirm');
|
||||
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!groupId) {
|
||||
$("#group_avatar_preview img").attr("src", default_avatar);
|
||||
$("#rm_group_restore_avatar").hide();
|
||||
return;
|
||||
}
|
||||
|
||||
let _thisGroup = groups.find((x) => x.id == groupId);
|
||||
_thisGroup.avatar_url = '';
|
||||
$("#group_avatar_preview").empty().append(getGroupAvatar(_thisGroup));
|
||||
$("#rm_group_restore_avatar").hide();
|
||||
await editGroup(groupId, true, true);
|
||||
}
|
||||
|
||||
$(document).off("click", ".group_member .right_menu_button");
|
||||
$(document).on("click", ".group_member .right_menu_button", async function (event) {
|
||||
event.stopPropagation();
|
||||
const action = $(this).data('action');
|
||||
const member = $(this).closest('.group_member');
|
||||
|
||||
if (action === 'remove') {
|
||||
await modifyGroupMember(groupId, member, true);
|
||||
}
|
||||
|
||||
if (action === 'add') {
|
||||
await modifyGroupMember(groupId, member, false);
|
||||
}
|
||||
|
||||
if (action === 'enable') {
|
||||
member.removeClass('disabled');
|
||||
const _thisGroup = groups.find(x => x.id === groupId);
|
||||
const index = _thisGroup.disabled_members.indexOf(member.data('id'));
|
||||
if (index !== -1) {
|
||||
_thisGroup.disabled_members.splice(index, 1);
|
||||
}
|
||||
await editGroup(groupId);
|
||||
}
|
||||
|
||||
if (action === 'disable') {
|
||||
member.addClass('disabled');
|
||||
const _thisGroup = groups.find(x => x.id === groupId);
|
||||
_thisGroup.disabled_members.push(member.data('id'));
|
||||
await editGroup(groupId);
|
||||
}
|
||||
|
||||
if (action === 'up' || action === 'down') {
|
||||
await reorderGroupMember(groupId, member, action);
|
||||
}
|
||||
|
||||
if (action === 'view') {
|
||||
openCharacterDefinition(member);
|
||||
}
|
||||
|
||||
if (action === 'speak') {
|
||||
const chid = Number(member.attr('chid'));
|
||||
if (Number.isInteger(chid)) {
|
||||
Generate('normal', { force_chid: chid });
|
||||
}
|
||||
}
|
||||
|
||||
sortGroupMembers("#rm_group_add_members .group_member");
|
||||
await eventSource.emit(event_types.GROUP_UPDATED);
|
||||
const e = await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = resolve;
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
eventSource.emit('groupSelected', {detail: {id: groupId, group: group}});
|
||||
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
|
||||
|
||||
const croppedImage = await callPopup(getCropPopup(e.target.result), 'avatarToCrop');
|
||||
|
||||
if (!croppedImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const thumbnail = await createThumbnail(croppedImage, 96, 144);
|
||||
|
||||
if (!openGroupId) {
|
||||
$('#group_avatar_preview img').attr('src', thumbnail);
|
||||
$('#rm_group_restore_avatar').show();
|
||||
return;
|
||||
}
|
||||
|
||||
let _thisGroup = groups.find((x) => x.id == openGroupId);
|
||||
_thisGroup.avatar_url = thumbnail;
|
||||
$("#group_avatar_preview").empty().append(getGroupAvatar(_thisGroup));
|
||||
$("#rm_group_restore_avatar").show();
|
||||
await editGroup(openGroupId, true, true);
|
||||
}
|
||||
|
||||
async function restoreGroupAvatar() {
|
||||
const confirm = await callPopup('<h3>Are you sure you want to restore the group avatar?</h3> Your custom image will be deleted, and a collage will be used instead.', 'confirm');
|
||||
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!openGroupId) {
|
||||
$("#group_avatar_preview img").attr("src", default_avatar);
|
||||
$("#rm_group_restore_avatar").hide();
|
||||
return;
|
||||
}
|
||||
|
||||
let _thisGroup = groups.find((x) => x.id == openGroupId);
|
||||
_thisGroup.avatar_url = '';
|
||||
$("#group_avatar_preview").empty().append(getGroupAvatar(_thisGroup));
|
||||
$("#rm_group_restore_avatar").hide();
|
||||
await editGroup(openGroupId, true, true);
|
||||
}
|
||||
|
||||
async function onGroupActionClick(event) {
|
||||
event.stopPropagation();
|
||||
const action = $(this).data('action');
|
||||
const member = $(this).closest('.group_member');
|
||||
|
||||
if (action === 'remove') {
|
||||
await modifyGroupMember(openGroupId, member, true);
|
||||
}
|
||||
|
||||
if (action === 'add') {
|
||||
await modifyGroupMember(openGroupId, member, false);
|
||||
}
|
||||
|
||||
if (action === 'enable') {
|
||||
member.removeClass('disabled');
|
||||
const _thisGroup = groups.find(x => x.id === openGroupId);
|
||||
const index = _thisGroup.disabled_members.indexOf(member.data('id'));
|
||||
if (index !== -1) {
|
||||
_thisGroup.disabled_members.splice(index, 1);
|
||||
}
|
||||
await editGroup(openGroupId, false, false);
|
||||
}
|
||||
|
||||
if (action === 'disable') {
|
||||
member.addClass('disabled');
|
||||
const _thisGroup = groups.find(x => x.id === openGroupId);
|
||||
_thisGroup.disabled_members.push(member.data('id'));
|
||||
await editGroup(openGroupId, false, false);
|
||||
}
|
||||
|
||||
if (action === 'up' || action === 'down') {
|
||||
await reorderGroupMember(openGroupId, member, action);
|
||||
}
|
||||
|
||||
if (action === 'view') {
|
||||
openCharacterDefinition(member);
|
||||
}
|
||||
|
||||
if (action === 'speak') {
|
||||
const chid = Number(member.attr('chid'));
|
||||
if (Number.isInteger(chid)) {
|
||||
Generate('normal', { force_chid: chid });
|
||||
}
|
||||
}
|
||||
|
||||
await eventSource.emit(event_types.GROUP_UPDATED);
|
||||
}
|
||||
|
||||
function updateFavButtonState(state) {
|
||||
@ -1235,10 +1281,7 @@ async function createGroup() {
|
||||
let name = $("#rm_group_chat_name").val();
|
||||
let allow_self_responses = !!$("#rm_group_allow_self_responses").prop("checked");
|
||||
let activation_strategy = $('input[name="rm_group_activation_strategy"]:checked').val() ?? group_activation_strategy.NATURAL;
|
||||
const members = $("#rm_group_members .group_member")
|
||||
.map((_, x) => $(x).data("id"))
|
||||
.toArray();
|
||||
|
||||
const members = newGroupMembers;
|
||||
const memberNames = characters.filter(x => members.includes(x.avatar)).map(x => x.name).join(", ");
|
||||
|
||||
if (!name) {
|
||||
@ -1268,6 +1311,7 @@ async function createGroup() {
|
||||
});
|
||||
|
||||
if (createGroupResponse.ok) {
|
||||
newGroupMembers = [];
|
||||
const data = await createGroupResponse.json();
|
||||
createTagMapFromList("#groupTagList", data.id);
|
||||
await getCharacters();
|
||||
@ -1351,9 +1395,8 @@ export async function openGroupChat(groupId, chatId) {
|
||||
group['date_last_chat'] = Date.now();
|
||||
updateChatMetadata(group.chat_metadata, true);
|
||||
|
||||
await editGroup(groupId, true);
|
||||
await editGroup(groupId, true, false);
|
||||
await getGroupChat(groupId);
|
||||
sortCharactersList();
|
||||
}
|
||||
|
||||
export async function renameGroupChat(groupId, oldChatId, newChatId) {
|
||||
@ -1445,7 +1488,7 @@ export async function saveGroupBookmarkChat(groupId, name, metadata, mesId) {
|
||||
? chat.slice(0, parseInt(mesId) + 1)
|
||||
: chat;
|
||||
|
||||
await editGroup(groupId, true);
|
||||
await editGroup(groupId, true, false);
|
||||
|
||||
await fetch("/savegroupchat", {
|
||||
method: "POST",
|
||||
@ -1513,4 +1556,12 @@ jQuery(() => {
|
||||
});
|
||||
$("#send_textarea").on("keyup", onSendTextareaInput);
|
||||
$("#groupCurrentMemberPopoutButton").on('click', doCurMemberListPopout);
|
||||
$("#rm_group_chat_name").on("input", onGroupNameInput)
|
||||
$("#rm_group_delete").off().on("click", onDeleteGroupClick);
|
||||
$("#group_favorite_button").on('click', onFavoriteGroupClick);
|
||||
$("#rm_group_allow_self_responses").on("input", onGroupSelfResponsesClick);
|
||||
$('input[name="rm_group_activation_strategy"]').on("input", onGroupActivationStrategyInput);
|
||||
$("#group_avatar_button").on("input", uploadGroupAvatar);
|
||||
$("#rm_group_restore_avatar").on("click", restoreGroupAvatar);
|
||||
$(document).on("click", ".group_member .right_menu_button", onGroupActionClick);
|
||||
});
|
||||
|
5972
public/scripts/handlebars.js
Normal file
5972
public/scripts/handlebars.js
Normal file
File diff suppressed because one or more lines are too long
@ -7,6 +7,7 @@ import {
|
||||
import {
|
||||
power_user,
|
||||
} from "./power-user.js";
|
||||
import { getSortableDelay } from "./utils.js";
|
||||
|
||||
export {
|
||||
kai_settings,
|
||||
@ -243,7 +244,7 @@ function sortItemsByOrder(orderArray) {
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
jQuery(function () {
|
||||
sliders.forEach(slider => {
|
||||
$(document).on("input", slider.sliderId, function () {
|
||||
const value = $(this).val();
|
||||
@ -267,6 +268,7 @@ $(document).ready(function () {
|
||||
});
|
||||
|
||||
$('#kobold_order').sortable({
|
||||
delay: getSortableDelay(),
|
||||
stop: function () {
|
||||
const order = [];
|
||||
$('#kobold_order').children().each(function () {
|
||||
|
@ -1,12 +1,19 @@
|
||||
import {
|
||||
getRequestHeaders,
|
||||
saveSettingsDebounced,
|
||||
getStoppingStrings,
|
||||
getTextTokens
|
||||
getTextTokens,
|
||||
max_context,
|
||||
novelai_setting_names,
|
||||
saveSettingsDebounced,
|
||||
setGenerationParamsFromPreset
|
||||
} from "../script.js";
|
||||
import { getCfg } from "./extensions/cfg/util.js";
|
||||
import { tokenizers } from "./power-user.js";
|
||||
import { getStringHash } from "./utils.js";
|
||||
import { MAX_CONTEXT_DEFAULT, tokenizers } from "./power-user.js";
|
||||
import {
|
||||
getSortableDelay,
|
||||
getStringHash,
|
||||
uuidv4,
|
||||
} from "./utils.js";
|
||||
|
||||
export {
|
||||
nai_settings,
|
||||
@ -16,29 +23,37 @@ export {
|
||||
};
|
||||
|
||||
const default_preamble = "[ Style: chat, complex, sensory, visceral ]";
|
||||
const default_order = [1, 5, 0, 2, 3, 4];
|
||||
const maximum_output_length = 150;
|
||||
const default_presets = {
|
||||
"euterpe-v2": "Classic-Euterpe",
|
||||
"krake-v2": "Classic-Krake",
|
||||
"clio-v1": "Talker-Chat-Clio",
|
||||
"kayra-v1": "Carefree-Kayra"
|
||||
}
|
||||
|
||||
const nai_settings = {
|
||||
temperature: 0.5,
|
||||
repetition_penalty: 1,
|
||||
repetition_penalty_range: 100,
|
||||
repetition_penalty_slope: 0,
|
||||
temperature: 1.5,
|
||||
repetition_penalty: 2.25,
|
||||
repetition_penalty_range: 2048,
|
||||
repetition_penalty_slope: 0.09,
|
||||
repetition_penalty_frequency: 0,
|
||||
repetition_penalty_presence: 0,
|
||||
tail_free_sampling: 0.68,
|
||||
top_k: 0,
|
||||
top_p: 1,
|
||||
top_a: 1,
|
||||
top_g: 0,
|
||||
typical_p: 1,
|
||||
min_length: 0,
|
||||
model_novel: "euterpe-v2",
|
||||
preset_settings_novel: "Classic-Euterpe",
|
||||
repetition_penalty_presence: 0.005,
|
||||
tail_free_sampling: 0.975,
|
||||
top_k: 10,
|
||||
top_p: 0.75,
|
||||
top_a: 0.08,
|
||||
typical_p: 0.975,
|
||||
min_length: 1,
|
||||
model_novel: "clio-v1",
|
||||
preset_settings_novel: "Talker-Chat-Clio",
|
||||
streaming_novel: false,
|
||||
nai_preamble: default_preamble,
|
||||
preamble: default_preamble,
|
||||
prefix: '',
|
||||
cfg_uc: '',
|
||||
banned_tokens: '',
|
||||
order: default_order,
|
||||
logit_bias: [],
|
||||
};
|
||||
|
||||
const nai_tiers = {
|
||||
@ -50,6 +65,7 @@ const nai_tiers = {
|
||||
|
||||
let novel_data = null;
|
||||
let badWordsCache = {};
|
||||
let biasCache = undefined;
|
||||
|
||||
export function setNovelData(data) {
|
||||
novel_data = data;
|
||||
@ -73,16 +89,17 @@ function getNovelTier(tier) {
|
||||
}
|
||||
|
||||
function loadNovelPreset(preset) {
|
||||
$("#amount_gen").val(preset.max_length);
|
||||
$("#amount_gen_counter").text(`${preset.max_length}`);
|
||||
if (((preset.max_context > 2048) && (!$("#max_context_unlocked")[0].checked)) ||
|
||||
((preset.max_context <= 2048) && ($("#max_context_unlocked")[0].checked))) {
|
||||
$("#max_context_unlocked").click();
|
||||
if (preset.genamt === undefined) {
|
||||
const needsUnlock = preset.max_context > MAX_CONTEXT_DEFAULT;
|
||||
$("#amount_gen").val(preset.max_length).trigger('input');
|
||||
$('#max_context_unlocked').prop('checked', needsUnlock).trigger('change');
|
||||
$("#max_context").val(preset.max_context).trigger('input');
|
||||
}
|
||||
else {
|
||||
setGenerationParamsFromPreset(preset);
|
||||
}
|
||||
$("#max_context").val(preset.max_context);
|
||||
$("#max_context_counter").text(`${preset.max_context}`);
|
||||
$("#rep_pen_size_novel").attr('max', preset.max_context);
|
||||
|
||||
$("#rep_pen_size_novel").attr('max', max_context);
|
||||
nai_settings.temperature = preset.temperature;
|
||||
nai_settings.repetition_penalty = preset.repetition_penalty;
|
||||
nai_settings.repetition_penalty_range = preset.repetition_penalty_range;
|
||||
@ -97,12 +114,14 @@ function loadNovelPreset(preset) {
|
||||
nai_settings.min_length = preset.min_length;
|
||||
nai_settings.cfg_scale = preset.cfg_scale;
|
||||
nai_settings.phrase_rep_pen = preset.phrase_rep_pen;
|
||||
nai_settings.top_g = preset.top_g;
|
||||
nai_settings.mirostat_lr = preset.mirostat_lr;
|
||||
nai_settings.mirostat_tau = preset.mirostat_tau;
|
||||
nai_settings.prefix = preset.prefix;
|
||||
nai_settings.cfg_uc = preset.cfg_uc || '';
|
||||
nai_settings.banned_tokens = preset.banned_tokens || '';
|
||||
nai_settings.order = preset.order || default_order;
|
||||
nai_settings.logit_bias = preset.logit_bias || [];
|
||||
nai_settings.preamble = preset.preamble || default_preamble;
|
||||
loadNovelSettingsUi(nai_settings);
|
||||
}
|
||||
|
||||
@ -112,7 +131,10 @@ function loadNovelSettings(settings) {
|
||||
$(`#model_novel_select option[value=${nai_settings.model_novel}]`).attr("selected", true);
|
||||
$('#model_novel_select').val(nai_settings.model_novel);
|
||||
|
||||
if (settings.nai_preamble !== undefined) nai_settings.preamble = settings.nai_preamble;
|
||||
if (settings.nai_preamble !== undefined) {
|
||||
nai_settings.preamble = settings.nai_preamble;
|
||||
delete settings.nai_preamble;
|
||||
}
|
||||
nai_settings.preset_settings_novel = settings.preset_settings_novel;
|
||||
nai_settings.temperature = settings.temperature;
|
||||
nai_settings.repetition_penalty = settings.repetition_penalty;
|
||||
@ -128,7 +150,6 @@ function loadNovelSettings(settings) {
|
||||
nai_settings.min_length = settings.min_length;
|
||||
nai_settings.phrase_rep_pen = settings.phrase_rep_pen;
|
||||
nai_settings.cfg_scale = settings.cfg_scale;
|
||||
nai_settings.top_g = settings.top_g;
|
||||
nai_settings.mirostat_lr = settings.mirostat_lr;
|
||||
nai_settings.mirostat_tau = settings.mirostat_tau;
|
||||
nai_settings.streaming_novel = !!settings.streaming_novel;
|
||||
@ -136,6 +157,8 @@ function loadNovelSettings(settings) {
|
||||
nai_settings.prefix = settings.prefix;
|
||||
nai_settings.cfg_uc = settings.cfg_uc || '';
|
||||
nai_settings.banned_tokens = settings.banned_tokens || '';
|
||||
nai_settings.order = settings.order || default_order;
|
||||
nai_settings.logit_bias = settings.logit_bias || [];
|
||||
loadNovelSettingsUi(nai_settings);
|
||||
}
|
||||
|
||||
@ -145,6 +168,7 @@ function loadNovelSettingsUi(ui_settings) {
|
||||
$("#rep_pen_novel").val(ui_settings.repetition_penalty);
|
||||
$("#rep_pen_counter_novel").text(Number(ui_settings.repetition_penalty).toFixed(2));
|
||||
$("#rep_pen_size_novel").val(ui_settings.repetition_penalty_range);
|
||||
$("#rep_pen_size_novel").attr('max', max_context);
|
||||
$("#rep_pen_size_counter_novel").text(Number(ui_settings.repetition_penalty_range).toFixed(0));
|
||||
$("#rep_pen_slope_novel").val(ui_settings.repetition_penalty_slope);
|
||||
$("#rep_pen_slope_counter_novel").text(Number(`${ui_settings.repetition_penalty_slope}`).toFixed(2));
|
||||
@ -165,20 +189,20 @@ function loadNovelSettingsUi(ui_settings) {
|
||||
$("#cfg_scale_novel").val(ui_settings.cfg_scale);
|
||||
$("#cfg_scale_counter_novel").text(Number(ui_settings.cfg_scale).toFixed(2));
|
||||
$("#phrase_rep_pen_novel").val(ui_settings.phrase_rep_pen || "off");
|
||||
$("#top_g_novel").val(ui_settings.top_g);
|
||||
$("#top_g_counter_novel").text(Number(ui_settings.top_g).toFixed(0));
|
||||
$("#mirostat_lr_novel").val(ui_settings.mirostat_lr);
|
||||
$("#mirostat_lr_counter_novel").text(Number(ui_settings.mirostat_lr).toFixed(2));
|
||||
$("#mirostat_tau_novel").val(ui_settings.mirostat_tau);
|
||||
$("#mirostat_tau_counter_novel").text(Number(ui_settings.mirostat_tau).toFixed(2));
|
||||
$("#min_length_novel").val(ui_settings.min_length);
|
||||
$("#min_length_counter_novel").text(Number(ui_settings.min_length).toFixed(0));
|
||||
$('#nai_preamble_textarea').val(ui_settings.nai_preamble);
|
||||
$('#nai_preamble_textarea').val(ui_settings.preamble);
|
||||
$('#nai_prefix').val(ui_settings.prefix || "vanilla");
|
||||
$('#nai_cfg_uc').val(ui_settings.cfg_uc || "");
|
||||
$('#nai_banned_tokens').val(ui_settings.banned_tokens || "");
|
||||
|
||||
$("#streaming_novel").prop('checked', ui_settings.streaming_novel);
|
||||
sortItemsByOrder(ui_settings.order);
|
||||
displayLogitBias(ui_settings.logit_bias);
|
||||
}
|
||||
|
||||
const sliders = [
|
||||
@ -248,12 +272,6 @@ const sliders = [
|
||||
format: (val) => Number(val).toFixed(2),
|
||||
setValue: (val) => { nai_settings.typical_p = Number(val).toFixed(2); },
|
||||
},
|
||||
{
|
||||
sliderId: "#top_g_novel",
|
||||
counterId: "#top_g_counter_novel",
|
||||
format: (val) => Number(val).toFixed(0),
|
||||
setValue: (val) => { nai_settings.top_g = Number(val).toFixed(0); },
|
||||
},
|
||||
{
|
||||
sliderId: "#mirostat_tau_novel",
|
||||
counterId: "#mirostat_tau_counter_novel",
|
||||
@ -394,6 +412,12 @@ export function getNovelGenerationData(finalPrompt, this_settings, this_amount_g
|
||||
const prefix = selectPrefix(nai_settings.prefix, finalPrompt);
|
||||
const cfgSettings = getCfg();
|
||||
|
||||
let logitBias = [];
|
||||
if (tokenizerType !== tokenizers.NONE && Array.isArray(nai_settings.logit_bias) && nai_settings.logit_bias.length) {
|
||||
logitBias = biasCache || calculateLogitBias();
|
||||
biasCache = logitBias;
|
||||
}
|
||||
|
||||
return {
|
||||
"input": finalPrompt,
|
||||
"model": nai_settings.model_novel,
|
||||
@ -411,21 +435,20 @@ export function getNovelGenerationData(finalPrompt, this_settings, this_amount_g
|
||||
"top_p": parseFloat(nai_settings.top_p),
|
||||
"top_k": parseInt(nai_settings.top_k),
|
||||
"typical_p": parseFloat(nai_settings.typical_p),
|
||||
"top_g": parseFloat(nai_settings.top_g),
|
||||
"mirostat_lr": parseFloat(nai_settings.mirostat_lr),
|
||||
"mirostat_tau": parseFloat(nai_settings.mirostat_tau),
|
||||
"cfg_scale": cfgSettings?.guidanceScale ?? parseFloat(nai_settings.cfg_scale),
|
||||
"cfg_uc": cfgSettings?.negativePrompt ?? nai_settings.cfg_uc ?? "",
|
||||
"cfg_uc": cfgSettings?.negativePrompt ?? nai_settings.cfg_uc ?? "",
|
||||
"phrase_rep_pen": nai_settings.phrase_rep_pen,
|
||||
"stop_sequences": stopSequences,
|
||||
"bad_words_ids": badWordIds,
|
||||
"logit_bias_exp": logitBias,
|
||||
"generate_until_sentence": true,
|
||||
"use_cache": false,
|
||||
"use_string": true,
|
||||
"return_full_text": false,
|
||||
"prefix": prefix,
|
||||
"order": this_settings.order,
|
||||
"streaming": nai_settings.streaming_novel,
|
||||
"order": nai_settings.order || this_settings.order || default_order,
|
||||
};
|
||||
}
|
||||
|
||||
@ -446,7 +469,129 @@ function selectPrefix(selected_prefix, finalPromt) {
|
||||
return "vanilla";
|
||||
}
|
||||
|
||||
// Sort the samplers by the order array
|
||||
function sortItemsByOrder(orderArray) {
|
||||
console.debug('Preset samplers order: ' + orderArray);
|
||||
const $draggableItems = $("#novel_order");
|
||||
|
||||
// Sort the items by the order array
|
||||
for (let i = 0; i < orderArray.length; i++) {
|
||||
const index = orderArray[i];
|
||||
const $item = $draggableItems.find(`[data-id="${index}"]`).detach();
|
||||
$draggableItems.append($item);
|
||||
}
|
||||
|
||||
// Update the disabled class for each sampler
|
||||
$draggableItems.children().each(function () {
|
||||
const isEnabled = orderArray.includes(parseInt($(this).data('id')));
|
||||
$(this).toggleClass('disabled', !isEnabled);
|
||||
|
||||
// If the sampler is disabled, move it to the bottom of the list
|
||||
if (!isEnabled) {
|
||||
const item = $(this).detach();
|
||||
$draggableItems.append(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function saveSamplingOrder() {
|
||||
const order = [];
|
||||
$('#novel_order').children().each(function () {
|
||||
const isEnabled = !$(this).hasClass('disabled');
|
||||
if (isEnabled) {
|
||||
order.push($(this).data('id'));
|
||||
}
|
||||
});
|
||||
nai_settings.order = order;
|
||||
console.log('Samplers reordered:', nai_settings.order);
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
function displayLogitBias(logit_bias) {
|
||||
if (!Array.isArray(logit_bias)) {
|
||||
console.log('Logit bias set not found');
|
||||
return;
|
||||
}
|
||||
|
||||
$('.novelai_logit_bias_list').empty();
|
||||
|
||||
for (const entry of logit_bias) {
|
||||
if (entry) {
|
||||
createLogitBiasListItem(entry);
|
||||
}
|
||||
}
|
||||
|
||||
biasCache = undefined;
|
||||
}
|
||||
|
||||
function createNewLogitBiasEntry() {
|
||||
const entry = { id: uuidv4(), text: '', value: 0 };
|
||||
nai_settings.logit_bias.push(entry);
|
||||
biasCache = undefined;
|
||||
createLogitBiasListItem(entry);
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
function createLogitBiasListItem(entry) {
|
||||
const id = entry.id;
|
||||
const template = $('#novelai_logit_bias_template .novelai_logit_bias_form').clone();
|
||||
template.data('id', id);
|
||||
template.find('.novelai_logit_bias_text').val(entry.text).on('input', function () {
|
||||
entry.text = $(this).val();
|
||||
biasCache = undefined;
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
template.find('.novelai_logit_bias_value').val(entry.value).on('input', function () {
|
||||
entry.value = Number($(this).val());
|
||||
biasCache = undefined;
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
template.find('.novelai_logit_bias_remove').on('click', function () {
|
||||
$(this).closest('.novelai_logit_bias_form').remove();
|
||||
const index = nai_settings.logit_bias.indexOf(entry);
|
||||
if (index > -1) {
|
||||
nai_settings.logit_bias.splice(index, 1);
|
||||
}
|
||||
biasCache = undefined;
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
$('.novelai_logit_bias_list').prepend(template);
|
||||
}
|
||||
|
||||
function calculateLogitBias() {
|
||||
const bias_preset = nai_settings.logit_bias;
|
||||
|
||||
if (!Array.isArray(bias_preset) || bias_preset.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const clio = nai_settings.model_novel.includes('clio');
|
||||
const kayra = nai_settings.model_novel.includes('kayra');
|
||||
const tokenizerType = kayra ? tokenizers.NERD2 : (clio ? tokenizers.NERD : tokenizers.NONE);
|
||||
|
||||
return bias_preset.filter(b => b.text?.length > 0).map(bias => ({
|
||||
bias: bias.value,
|
||||
ensure_sequence_finish: false,
|
||||
generate_once: false,
|
||||
sequence: getTextTokens(tokenizerType, bias.text)
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms instruction into compatible format for Novel AI.
|
||||
* 1. Instruction must begin and end with curly braces followed and preceded by a space.
|
||||
* 2. Instruction must not contain square brackets as it serves different purpose in NAI.
|
||||
* @param {string} prompt Original instruction prompt
|
||||
* @returns Processed prompt
|
||||
*/
|
||||
export function adjustNovelInstructionPrompt(prompt) {
|
||||
const stripedPrompt = prompt.replace(/[\[\]]/g, '').trim();
|
||||
return `{ ${stripedPrompt} }`;
|
||||
}
|
||||
|
||||
export async function generateNovelWithStreaming(generate_data, signal) {
|
||||
generate_data.streaming = nai_settings.streaming_novel;
|
||||
|
||||
const response = await fetch('/generate_novelai', {
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify(generate_data),
|
||||
@ -499,14 +644,13 @@ $("#nai_preamble_restore").on('click', function () {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
jQuery(function () {
|
||||
sliders.forEach(slider => {
|
||||
$(document).on("input", slider.sliderId, function () {
|
||||
const value = $(this).val();
|
||||
const formattedValue = slider.format(value);
|
||||
slider.setValue(value);
|
||||
$(slider.counterId).text(formattedValue);
|
||||
console.log('saving');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
});
|
||||
@ -520,6 +664,12 @@ $(document).ready(function () {
|
||||
$("#model_novel_select").change(function () {
|
||||
nai_settings.model_novel = $("#model_novel_select").find(":selected").val();
|
||||
saveSettingsDebounced();
|
||||
|
||||
// Update the selected preset to something appropriate
|
||||
const default_preset = default_presets[nai_settings.model_novel];
|
||||
$(`#settings_perset_novel`).val(novelai_setting_names[default_preset]);
|
||||
$(`#settings_perset_novel option[value=${novelai_setting_names[default_preset]}]`).attr("selected", "true")
|
||||
$(`#settings_perset_novel`).trigger("change");
|
||||
});
|
||||
|
||||
$("#nai_prefix").on('change', function () {
|
||||
@ -531,4 +681,19 @@ $(document).ready(function () {
|
||||
nai_settings.phrase_rep_pen = $("#phrase_rep_pen_novel").find(":selected").val();
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#novel_order').sortable({
|
||||
delay: getSortableDelay(),
|
||||
stop: saveSamplingOrder,
|
||||
});
|
||||
|
||||
$('#novel_order .toggle_button').on('click', function () {
|
||||
const $item = $(this).closest('[data-id]');
|
||||
const isEnabled = !$item.hasClass('disabled');
|
||||
$item.toggleClass('disabled', isEnabled);
|
||||
console.log('Sampler toggled:', $item.data('id'), !isEnabled);
|
||||
saveSamplingOrder();
|
||||
});
|
||||
|
||||
$("#novelai_logit_bias_new_entry").on("click", createNewLogitBiasEntry);
|
||||
});
|
||||
|
@ -47,7 +47,7 @@ import {
|
||||
import {
|
||||
delay,
|
||||
download,
|
||||
getFileText,
|
||||
getFileText, getSortableDelay,
|
||||
getStringHash,
|
||||
parseJsonFile,
|
||||
stringFormat,
|
||||
@ -341,7 +341,7 @@ function setupChatCompletionPromptManager(openAiSettings) {
|
||||
containerIdentifier: 'completion_prompt_manager',
|
||||
listIdentifier: 'completion_prompt_manager_list',
|
||||
toggleDisabled: ['main'],
|
||||
draggable: true,
|
||||
sortableDelay: getSortableDelay(),
|
||||
defaultPrompts: {
|
||||
main: default_main_prompt,
|
||||
nsfw: default_nsfw_prompt,
|
||||
|
1190
public/scripts/pagination.js
Normal file
1190
public/scripts/pagination.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,6 @@ import {
|
||||
reloadCurrentChat,
|
||||
getRequestHeaders,
|
||||
substituteParams,
|
||||
updateVisibleDivs,
|
||||
eventSource,
|
||||
event_types,
|
||||
getCurrentChatId,
|
||||
@ -18,7 +17,7 @@ import {
|
||||
setCharacterId,
|
||||
setEditedMessageId
|
||||
} from "../script.js";
|
||||
import { favsToHotswap, isMobile, initMovingUI } from "./RossAscends-mods.js";
|
||||
import { isMobile, initMovingUI } from "./RossAscends-mods.js";
|
||||
import {
|
||||
groups,
|
||||
resetSelectedGroup,
|
||||
@ -34,8 +33,7 @@ export {
|
||||
loadMovingUIState,
|
||||
collapseNewlines,
|
||||
playMessageSound,
|
||||
sortGroupMembers,
|
||||
sortCharactersList,
|
||||
sortEntitiesList,
|
||||
fixMarkdown,
|
||||
power_user,
|
||||
pygmalion_options,
|
||||
@ -46,6 +44,12 @@ export {
|
||||
export const MAX_CONTEXT_DEFAULT = 4096;
|
||||
const MAX_CONTEXT_UNLOCKED = 65536;
|
||||
|
||||
const defaultStoryString = `{{#if description}}{{description}}{{/if}}
|
||||
{{#if personality}}{{personality}}{{/if}}
|
||||
{{#if scenario}}Scenario: {{scenario}}{{/if}}`;
|
||||
const defaultExampleSeparator = '***';
|
||||
const defaultChatStart = '***';
|
||||
|
||||
const avatar_styles = {
|
||||
ROUND: 0,
|
||||
RECTANGULAR: 1,
|
||||
@ -93,11 +97,6 @@ let power_user = {
|
||||
collapse_newlines: false,
|
||||
pygmalion_formatting: pygmalion_options.AUTO,
|
||||
pin_examples: false,
|
||||
disable_description_formatting: false,
|
||||
disable_scenario_formatting: false,
|
||||
disable_personality_formatting: false,
|
||||
disable_examples_formatting: false,
|
||||
disable_start_formatting: false,
|
||||
trim_sentences: false,
|
||||
include_newline: false,
|
||||
always_force_name2: false,
|
||||
@ -106,7 +105,6 @@ let power_user = {
|
||||
multigen: false,
|
||||
multigen_first_chunk: 50,
|
||||
multigen_next_chunks: 30,
|
||||
custom_chat_separator: '',
|
||||
markdown_escape_strings: '',
|
||||
|
||||
fast_ui_mode: true,
|
||||
@ -176,12 +174,20 @@ let power_user = {
|
||||
stop_sequence: '',
|
||||
input_sequence: '### Instruction:',
|
||||
output_sequence: '### Response:',
|
||||
last_output_sequence: '',
|
||||
preset: 'Alpaca',
|
||||
separator_sequence: '',
|
||||
macro: false,
|
||||
names_force_groups: true,
|
||||
},
|
||||
|
||||
context: {
|
||||
preset: 'Default',
|
||||
story_string: defaultStoryString,
|
||||
chat_start: defaultChatStart,
|
||||
example_separator: defaultExampleSeparator,
|
||||
},
|
||||
|
||||
personas: {},
|
||||
default_persona: null,
|
||||
persona_descriptions: {},
|
||||
@ -200,8 +206,10 @@ let power_user = {
|
||||
let themes = [];
|
||||
let movingUIPresets = [];
|
||||
let instruct_presets = [];
|
||||
let context_presets = [];
|
||||
|
||||
const storage_keys = {
|
||||
ui_language: "language",
|
||||
fast_ui_mode: "TavernAI_fast_ui_mode",
|
||||
avatar_style: "TavernAI_avatar_style",
|
||||
chat_display: "TavernAI_chat_display",
|
||||
@ -661,6 +669,10 @@ function loadPowerUserSettings(settings, data) {
|
||||
instruct_presets = data.instruct;
|
||||
}
|
||||
|
||||
if (data.context !== undefined) {
|
||||
context_presets = data.context;
|
||||
}
|
||||
|
||||
// These are still local storage
|
||||
const fastUi = localStorage.getItem(storage_keys.fast_ui_mode);
|
||||
const movingUI = localStorage.getItem(storage_keys.movingUI);
|
||||
@ -719,16 +731,10 @@ function loadPowerUserSettings(settings, data) {
|
||||
$("#spoiler_free_mode").prop("checked", power_user.spoiler_free_mode);
|
||||
$("#collapse-newlines-checkbox").prop("checked", power_user.collapse_newlines);
|
||||
$("#pin-examples-checkbox").prop("checked", power_user.pin_examples);
|
||||
$("#disable-description-formatting-checkbox").prop("checked", power_user.disable_description_formatting);
|
||||
$("#disable-scenario-formatting-checkbox").prop("checked", power_user.disable_scenario_formatting);
|
||||
$("#disable-personality-formatting-checkbox").prop("checked", power_user.disable_personality_formatting);
|
||||
$("#always-force-name2-checkbox").prop("checked", power_user.always_force_name2);
|
||||
$("#disable-examples-formatting-checkbox").prop("checked", power_user.disable_examples_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);
|
||||
$("#custom_chat_separator").val(power_user.custom_chat_separator);
|
||||
$("#markdown_escape_strings").val(power_user.markdown_escape_strings);
|
||||
$("#fast_ui_mode").prop("checked", power_user.fast_ui_mode);
|
||||
$("#waifuMode").prop("checked", power_user.waifuMode);
|
||||
@ -795,15 +801,14 @@ function loadPowerUserSettings(settings, data) {
|
||||
|
||||
|
||||
$(`#character_sort_order option[data-order="${power_user.sort_order}"][data-field="${power_user.sort_field}"]`).prop("selected", true);
|
||||
sortCharactersList();
|
||||
reloadMarkdownProcessor(power_user.render_formulas);
|
||||
loadInstructMode();
|
||||
loadContextSettings();
|
||||
loadMaxContextUnlocked();
|
||||
switchWaifuMode();
|
||||
switchSpoilerMode();
|
||||
loadMovingUIState();
|
||||
loadCharListState();
|
||||
|
||||
}
|
||||
|
||||
async function loadCharListState() {
|
||||
@ -866,6 +871,61 @@ function switchMaxContextSize() {
|
||||
}
|
||||
}
|
||||
|
||||
function loadContextSettings() {
|
||||
const controls = [
|
||||
{ id: "context_story_string", property: "story_string", isCheckbox: false },
|
||||
{ id: "context_example_separator", property: "example_separator", isCheckbox: false },
|
||||
{ id: "context_chat_start", property: "chat_start", isCheckbox: false },
|
||||
];
|
||||
|
||||
controls.forEach(control => {
|
||||
const $element = $(`#${control.id}`);
|
||||
|
||||
if (control.isCheckbox) {
|
||||
$element.prop('checked', power_user.context[control.property]);
|
||||
} else {
|
||||
$element.val(power_user.context[control.property]);
|
||||
}
|
||||
|
||||
$element.on('input', function () {
|
||||
power_user.context[control.property] = control.isCheckbox ? !!$(this).prop('checked') : $(this).val();
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
});
|
||||
|
||||
context_presets.forEach((preset) => {
|
||||
const name = preset.name;
|
||||
const option = document.createElement('option');
|
||||
option.value = name;
|
||||
option.innerText = name;
|
||||
option.selected = name === power_user.context.preset;
|
||||
$('#context_presets').append(option);
|
||||
});
|
||||
|
||||
$('#context_presets').on('change', function () {
|
||||
const name = $(this).find(':selected').val();
|
||||
const preset = context_presets.find(x => x.name === name);
|
||||
|
||||
if (!preset) {
|
||||
return;
|
||||
}
|
||||
|
||||
power_user.context.preset = name;
|
||||
controls.forEach(control => {
|
||||
if (preset[control.property] !== undefined) {
|
||||
power_user.context[control.property] = preset[control.property];
|
||||
const $element = $(`#${control.id}`);
|
||||
|
||||
if (control.isCheckbox) {
|
||||
$element.prop('checked', power_user.context[control.property]).trigger('input');
|
||||
} else {
|
||||
$element.val(power_user.context[control.property]).trigger('input');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadInstructMode() {
|
||||
const controls = [
|
||||
{ id: "instruct_enabled", property: "enabled", isCheckbox: true },
|
||||
@ -879,6 +939,7 @@ function loadInstructMode() {
|
||||
{ id: "instruct_names", property: "names", isCheckbox: true },
|
||||
{ id: "instruct_macro", property: "macro", isCheckbox: true },
|
||||
{ id: "instruct_names_force_groups", property: "names_force_groups", isCheckbox: true },
|
||||
{ id: "instruct_last_output_sequence", property: "last_output_sequence", isCheckbox: false },
|
||||
];
|
||||
|
||||
if (power_user.instruct.names_force_groups === undefined) {
|
||||
@ -975,6 +1036,20 @@ export function fuzzySearchGroups(searchValue) {
|
||||
return ids;
|
||||
}
|
||||
|
||||
export function renderStoryString(params) {
|
||||
try {
|
||||
const compiledTemplate = Handlebars.compile(power_user.context.story_string, { noEscape: true });
|
||||
let output = compiledTemplate(params);
|
||||
output = substituteParams(output, params.user, params.char);
|
||||
output = `${output.trim()}\n`; // add a newline to the end
|
||||
return output;
|
||||
} catch (e) {
|
||||
toastr.error('Check the story string template for validity', 'Error rendering story string');
|
||||
console.error('Error rendering story string', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2) {
|
||||
let includeNames = isNarrator ? false : power_user.instruct.names;
|
||||
|
||||
@ -991,8 +1066,8 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata
|
||||
const separator = power_user.instruct.wrap ? '\n' : '';
|
||||
const separatorSequence = power_user.instruct.separator_sequence && !isUser
|
||||
? power_user.instruct.separator_sequence
|
||||
: (power_user.instruct.wrap ? '\n' : '');
|
||||
const textArray = includeNames ? [sequence, `${name}: ${mes}`, separatorSequence] : [sequence, mes, separatorSequence];
|
||||
: separator;
|
||||
const textArray = includeNames ? [sequence, `${name}: ${mes}` + separatorSequence] : [sequence, mes + separatorSequence];
|
||||
const text = textArray.filter(x => x).join(separator);
|
||||
return text;
|
||||
}
|
||||
@ -1010,7 +1085,8 @@ export function formatInstructStoryString(story, systemPrompt) {
|
||||
|
||||
export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2) {
|
||||
const includeNames = power_user.instruct.names || (!!selected_group && power_user.instruct.names_force_groups);
|
||||
let sequence = isImpersonate ? power_user.instruct.input_sequence : power_user.instruct.output_sequence;
|
||||
const getOutputSequence = () => power_user.instruct.last_output_sequence || power_user.instruct.output_sequence;
|
||||
let sequence = isImpersonate ? power_user.instruct.input_sequence : getOutputSequence();
|
||||
|
||||
if (power_user.instruct.macro) {
|
||||
sequence = substituteParams(sequence, name1, name2);
|
||||
@ -1049,46 +1125,13 @@ const compareFunc = (first, second) => {
|
||||
}
|
||||
};
|
||||
|
||||
function sortCharactersList() {
|
||||
const arr1 = groups.map(x => ({
|
||||
item: x,
|
||||
id: x.id,
|
||||
selector: '.group_select',
|
||||
attribute: 'grid',
|
||||
}))
|
||||
const arr2 = characters.map((x, index) => ({
|
||||
item: x,
|
||||
id: index,
|
||||
selector: '.character_select',
|
||||
attribute: 'chid',
|
||||
}));
|
||||
|
||||
const array = [...arr1, ...arr2];
|
||||
|
||||
if (power_user.sort_field == undefined || array.length === 0) {
|
||||
function sortEntitiesList(entities) {
|
||||
if (power_user.sort_field == undefined || entities.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let orderedList = array.slice().sort((a, b) => sortFunc(a.item, b.item));
|
||||
|
||||
for (const item of array) {
|
||||
$(`${item.selector}[${item.attribute}="${item.id}"]`).css({ 'order': orderedList.indexOf(item) });
|
||||
}
|
||||
updateVisibleDivs('#rm_print_characters_block', true);
|
||||
entities.sort((a, b) => sortFunc(a.item, b.item));
|
||||
}
|
||||
|
||||
function sortGroupMembers(selector) {
|
||||
if (power_user.sort_field == undefined || characters.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let orderedList = characters.slice().sort(sortFunc);
|
||||
|
||||
for (let i = 0; i < characters.length; i++) {
|
||||
$(`${selector}[chid="${i}"]`).css({ 'order': orderedList.indexOf(characters[i]) });
|
||||
}
|
||||
}
|
||||
|
||||
async function saveTheme() {
|
||||
const name = await callPopup('Enter a theme preset name:', 'input');
|
||||
|
||||
@ -1339,8 +1382,25 @@ function doResetPanels() {
|
||||
$("#movingUIreset").trigger('click');
|
||||
}
|
||||
|
||||
function addLanguagesToDropdown() {
|
||||
$.getJSON('i18n.json', function (data) {
|
||||
if (!Array.isArray(data?.lang)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const lang of data.lang) {
|
||||
const option = document.createElement('option');
|
||||
option.value = lang;
|
||||
option.innerText = lang;
|
||||
$('#ui_language_select').append(option);
|
||||
}
|
||||
|
||||
const selectedLanguage = localStorage.getItem(storage_keys.ui_language);
|
||||
if (selectedLanguage) {
|
||||
$('#ui_language_select').val(selectedLanguage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setAvgBG() {
|
||||
const bgimg = new Image();
|
||||
@ -1621,31 +1681,6 @@ $(document).ready(() => {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$("#disable-description-formatting-checkbox").change(function () {
|
||||
power_user.disable_description_formatting = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
})
|
||||
|
||||
$("#disable-scenario-formatting-checkbox").change(function () {
|
||||
power_user.disable_scenario_formatting = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$("#disable-personality-formatting-checkbox").change(function () {
|
||||
power_user.disable_personality_formatting = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$("#disable-examples-formatting-checkbox").change(function () {
|
||||
power_user.disable_examples_formatting = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
})
|
||||
|
||||
$("#disable-start-formatting-checkbox").change(function () {
|
||||
power_user.disable_start_formatting = !!$(this).prop('checked');
|
||||
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
|
||||
@ -1672,12 +1707,6 @@ $(document).ready(() => {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$("#custom_chat_separator").on('input', function () {
|
||||
power_user.custom_chat_separator = $(this).val();
|
||||
saveSettingsDebounced();
|
||||
reloadMarkdownProcessor(power_user.render_formulas);
|
||||
});
|
||||
|
||||
$("#markdown_escape_strings").on('input', function () {
|
||||
power_user.markdown_escape_strings = $(this).val();
|
||||
saveSettingsDebounced();
|
||||
@ -1834,6 +1863,7 @@ $(document).ready(() => {
|
||||
power_user.never_resize_avatars = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$("#show_card_avatar_urls").on('input', function () {
|
||||
power_user.show_card_avatar_urls = !!$(this).prop('checked');
|
||||
printCharacters();
|
||||
@ -1859,8 +1889,7 @@ $(document).ready(() => {
|
||||
power_user.sort_field = $(this).find(":selected").data('field');
|
||||
power_user.sort_order = $(this).find(":selected").data('order');
|
||||
power_user.sort_rule = $(this).find(":selected").data('rule');
|
||||
sortCharactersList();
|
||||
favsToHotswap();
|
||||
printCharacters();
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
@ -1972,12 +2001,6 @@ $(document).ready(() => {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
/* $("#removeXML").on("input", function () {
|
||||
power_user.removeXML = !!$(this).prop('checked');
|
||||
reloadCurrentChat();
|
||||
saveSettingsDebounced();
|
||||
}); */
|
||||
|
||||
$("#token_padding").on("input", function () {
|
||||
power_user.token_padding = Number($(this).val());
|
||||
saveSettingsDebounced();
|
||||
@ -2090,6 +2113,18 @@ $(document).ready(() => {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#ui_language_select').on('change', async function () {
|
||||
const language = $(this).val();
|
||||
|
||||
if (language) {
|
||||
localStorage.setItem(storage_keys.ui_language, language);
|
||||
} else {
|
||||
localStorage.removeItem(storage_keys.ui_language);
|
||||
}
|
||||
|
||||
location.reload();
|
||||
});
|
||||
|
||||
$(window).on('focus', function () {
|
||||
browser_has_focus = true;
|
||||
});
|
||||
@ -2105,4 +2140,5 @@ $(document).ready(() => {
|
||||
registerSlashCommand('cut', doMesCut, [], ' <span class="monospace">(requred number)</span> – cuts the specified message from the chat', true, true);
|
||||
registerSlashCommand('resetpanels', doResetPanels, ['resetui'], ' – resets UI panels to original state.', true, true);
|
||||
registerSlashCommand('bgcol', setAvgBG, [], ' – WIP test of auto-bg avg coloring', true, true);
|
||||
addLanguagesToDropdown();
|
||||
});
|
||||
|
@ -116,6 +116,12 @@ class PresetManager {
|
||||
<h3>Preset name:</h3>
|
||||
<h4>Hint: Use a character/group name to bind preset to a specific chat.</h4>`;
|
||||
const name = await callPopup(popupText, "input");
|
||||
|
||||
if (!name) {
|
||||
console.log('Preset name not provided');
|
||||
return;
|
||||
}
|
||||
|
||||
await this.savePreset(name);
|
||||
toastr.success('Preset saved');
|
||||
}
|
||||
@ -214,7 +220,16 @@ class PresetManager {
|
||||
}
|
||||
}
|
||||
|
||||
const filteredKeys = ['preset', 'streaming_url', 'stopping_strings', 'use_stop_sequence'];
|
||||
const filteredKeys = [
|
||||
'preset',
|
||||
'streaming_url',
|
||||
'stopping_strings',
|
||||
'use_stop_sequence',
|
||||
'preset_settings_novel',
|
||||
'streaming_novel',
|
||||
'nai_preamble',
|
||||
'model_novel',
|
||||
];
|
||||
const settings = Object.assign({}, getSettingsByApiId(this.apiId));
|
||||
|
||||
for (const key of filteredKeys) {
|
||||
|
@ -8,8 +8,12 @@ export const markdownExclusionExt = () => {
|
||||
}
|
||||
|
||||
let combinedExcludeString = '';
|
||||
if (power_user.custom_chat_separator) {
|
||||
combinedExcludeString += `${power_user.custom_chat_separator},`;
|
||||
if (power_user.context.chat_start) {
|
||||
combinedExcludeString += `${power_user.context.chat_start},`;
|
||||
}
|
||||
|
||||
if (power_user.context.example_separator) {
|
||||
combinedExcludeString += `${power_user.context.example_separator},`;
|
||||
}
|
||||
|
||||
if (power_user.markdown_escape_strings) {
|
||||
|
@ -4,19 +4,19 @@ import {
|
||||
this_chid,
|
||||
callPopup,
|
||||
menu_type,
|
||||
updateVisibleDivs,
|
||||
getCharacters,
|
||||
updateCharacterCount,
|
||||
entitiesFilter,
|
||||
} from "../script.js";
|
||||
import { FILTER_TYPES } from "./filters.js";
|
||||
|
||||
import { selected_group } from "./group-chats.js";
|
||||
import { groupCandidatesFilter, selected_group } from "./group-chats.js";
|
||||
import { uuidv4 } from "./utils.js";
|
||||
|
||||
export {
|
||||
tags,
|
||||
tag_map,
|
||||
loadTagsSettings,
|
||||
printTagFilters,
|
||||
isElementTagged,
|
||||
getTagsList,
|
||||
appendTagToList,
|
||||
createTagMapFromList,
|
||||
@ -24,19 +24,12 @@ export {
|
||||
importTags,
|
||||
};
|
||||
|
||||
const random_id = () => Math.round(Date.now() * Math.random()).toString();
|
||||
const TAG_LOGIC_AND = true; // switch to false to use OR logic for combining tags
|
||||
const CHARACTER_SELECTOR = '#rm_print_characters_block > div';
|
||||
const GROUP_MEMBER_SELECTOR = '#rm_group_add_members > div';
|
||||
const random_id = () => uuidv4();
|
||||
const CHARACTER_FILTER_SELECTOR = '#rm_characters_block .rm_tag_filter';
|
||||
const GROUP_FILTER_SELECTOR = '#rm_group_chats_block .rm_tag_filter';
|
||||
|
||||
function getCharacterSelector(listSelector) {
|
||||
if ($(listSelector).is(GROUP_FILTER_SELECTOR)) {
|
||||
return GROUP_MEMBER_SELECTOR;
|
||||
}
|
||||
|
||||
return CHARACTER_SELECTOR;
|
||||
function getFilterHelper(listSelector) {
|
||||
return $(listSelector).is(GROUP_FILTER_SELECTOR) ? groupCandidatesFilter : entitiesFilter;
|
||||
}
|
||||
|
||||
export const tag_filter_types = {
|
||||
@ -67,37 +60,20 @@ const DEFAULT_TAGS = [
|
||||
let tags = [];
|
||||
let tag_map = {};
|
||||
|
||||
function applyFavFilter(characterSelector) {
|
||||
function applyFavFilter(filterHelper) {
|
||||
const isSelected = $(this).hasClass('selected');
|
||||
const displayFavoritesOnly = !isSelected;
|
||||
|
||||
$(this).toggleClass('selected', displayFavoritesOnly);
|
||||
$(characterSelector).removeClass('hiddenByFav');
|
||||
|
||||
$(characterSelector).each(function () {
|
||||
if (displayFavoritesOnly) {
|
||||
if ($(this).find(".ch_fav").length !== 0) {
|
||||
const shouldBeDisplayed = $(this).find(".ch_fav").val().toLowerCase().includes(true);
|
||||
$(this).toggleClass('hiddenByFav', !shouldBeDisplayed);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
updateCharacterCount(characterSelector);
|
||||
updateVisibleDivs('#rm_print_characters_block', true);
|
||||
filterHelper.setFilterData(FILTER_TYPES.FAV, displayFavoritesOnly);
|
||||
}
|
||||
|
||||
function filterByGroups(characterSelector) {
|
||||
function filterByGroups(filterHelper) {
|
||||
const isSelected = $(this).hasClass('selected');
|
||||
const displayGroupsOnly = !isSelected;
|
||||
$(this).toggleClass('selected', displayGroupsOnly);
|
||||
$(characterSelector).removeClass('hiddenByGroup');
|
||||
|
||||
$(characterSelector).each((_, element) => {
|
||||
$(element).toggleClass('hiddenByGroup', displayGroupsOnly && !$(element).hasClass('group_select'));
|
||||
});
|
||||
updateCharacterCount(characterSelector);
|
||||
updateVisibleDivs('#rm_print_characters_block', true);
|
||||
filterHelper.setFilterData(FILTER_TYPES.GROUP, displayGroupsOnly);
|
||||
}
|
||||
|
||||
function loadTagsSettings(settings) {
|
||||
@ -290,7 +266,6 @@ function appendTagToList(listElement, tag, { removable, selectable, action, isGe
|
||||
return;
|
||||
}
|
||||
|
||||
const characterSelector = getCharacterSelector($(listElement));
|
||||
|
||||
let tagElement = $('#tag_template .tag').clone();
|
||||
tagElement.attr('id', tag.id);
|
||||
@ -315,11 +290,12 @@ function appendTagToList(listElement, tag, { removable, selectable, action, isGe
|
||||
}
|
||||
|
||||
if (selectable) {
|
||||
tagElement.on('click', () => onTagFilterClick.bind(tagElement)(listElement, characterSelector));
|
||||
tagElement.on('click', () => onTagFilterClick.bind(tagElement)(listElement));
|
||||
}
|
||||
|
||||
if (action) {
|
||||
tagElement.on('click', () => action.bind(tagElement)(characterSelector));
|
||||
const filter = getFilterHelper($(listElement));
|
||||
tagElement.on('click', () => action.bind(tagElement)(filter));
|
||||
tagElement.addClass('actionable');
|
||||
}
|
||||
if (action && tag.id === 2) {
|
||||
@ -329,7 +305,7 @@ function appendTagToList(listElement, tag, { removable, selectable, action, isGe
|
||||
$(listElement).append(tagElement);
|
||||
}
|
||||
|
||||
function onTagFilterClick(listElement, characterSelector) {
|
||||
function onTagFilterClick(listElement) {
|
||||
let excludeTag;
|
||||
if ($(this).hasClass('selected')) {
|
||||
$(this).removeClass('selected');
|
||||
@ -355,44 +331,10 @@ function onTagFilterClick(listElement, characterSelector) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Overhaul this somehow to use settings tag IDs instead
|
||||
const tagIds = [...($(listElement).find(".tag.selected:not(.actionable)").map((_, el) => $(el).attr("id")))];
|
||||
const excludedTagIds = [...($(listElement).find(".tag.excluded:not(.actionable)").map((_, el) => $(el).attr("id")))];
|
||||
$(characterSelector).each((_, element) => applyFilterToElement(tagIds, excludedTagIds, element));
|
||||
updateCharacterCount(characterSelector);
|
||||
updateVisibleDivs('#rm_print_characters_block', true);
|
||||
}
|
||||
|
||||
function applyFilterToElement(tagIds, excludedTagIds, element) {
|
||||
const tagFlags = tagIds.map(tagId => isElementTagged(element, tagId));
|
||||
const trueFlags = tagFlags.filter(x => x);
|
||||
const isTagged = TAG_LOGIC_AND ? tagFlags.length === trueFlags.length : trueFlags.length > 0;
|
||||
|
||||
const excludedTagFlags = excludedTagIds.map(tagId => isElementTagged(element, tagId));
|
||||
const isExcluded = excludedTagFlags.includes(true);
|
||||
|
||||
if (isExcluded) {
|
||||
$(element).addClass('hiddenByTag');
|
||||
} else if (tagIds.length > 0 && !isTagged) {
|
||||
$(element).addClass('hiddenByTag');
|
||||
} else {
|
||||
$(element).removeClass('hiddenByTag');
|
||||
}
|
||||
}
|
||||
|
||||
function isElementTagged(element, tagId) {
|
||||
const isGroup = $(element).hasClass('group_select');
|
||||
const isCharacter = $(element).hasClass('character_select') || $(element).hasClass('group_member');
|
||||
const idAttr = isGroup ? 'grid' : 'chid';
|
||||
const elementId = $(element).attr(idAttr);
|
||||
const lookupValue = isCharacter ? characters[elementId].avatar : elementId;
|
||||
const isTagged = Array.isArray(tag_map[lookupValue]) && tag_map[lookupValue].includes(tagId);
|
||||
return isTagged;
|
||||
}
|
||||
|
||||
function clearTagsFilter(characterSelector) {
|
||||
$('.rm_tag_filter .tag').removeClass('selected');
|
||||
$(characterSelector).removeClass('hiddenByTag');
|
||||
const filterHelper = getFilterHelper($(listElement));
|
||||
filterHelper.setFilterData(FILTER_TYPES.TAG, { excluded: excludedTagIds, selected: tagIds });
|
||||
}
|
||||
|
||||
function printTagFilters(type = tag_filter_types.character) {
|
||||
|
@ -8,6 +8,11 @@ export function isDigitsOnly(str) {
|
||||
return /^\d+$/.test(str);
|
||||
}
|
||||
|
||||
// Increase delay on touch screens
|
||||
export function getSortableDelay() {
|
||||
return navigator.maxTouchPoints > 0 ? 750 : 100;
|
||||
}
|
||||
|
||||
export function shuffle(array) {
|
||||
let currentIndex = array.length,
|
||||
randomIndex;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { saveSettings, callPopup, substituteParams, getTokenCount, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types } from "../script.js";
|
||||
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, delay, getCharaFilename, deepClone } from "./utils.js";
|
||||
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, deepClone, getSortableDelay, escapeRegex } from "./utils.js";
|
||||
import { getContext } from "./extensions.js";
|
||||
import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from "./authors-note.js";
|
||||
import { registerSlashCommand } from "./slash-commands.js";
|
||||
@ -302,6 +302,7 @@ function displayWorldEntries(name, data) {
|
||||
}
|
||||
|
||||
$("#world_popup_entries_list").sortable({
|
||||
delay: getSortableDelay(),
|
||||
handle: ".drag-handle",
|
||||
stop: async function (event, ui) {
|
||||
$('#world_popup_entries_list .world_entry').each(function (index) {
|
||||
@ -1129,7 +1130,7 @@ function matchKeys(haystack, needle) {
|
||||
return haystack.includes(transformedString);
|
||||
}
|
||||
else {
|
||||
const regex = new RegExp(`\\b${transformedString}\\b`);
|
||||
const regex = new RegExp(`\\b${escapeRegex(transformedString)}\\b`);
|
||||
if (regex.test(haystack)) {
|
||||
return true;
|
||||
}
|
||||
|
158
public/style.css
158
public/style.css
@ -1270,18 +1270,18 @@ input[type="file"] {
|
||||
filter: brightness(150%);
|
||||
}
|
||||
|
||||
#rm_character_count {
|
||||
padding: 5px;
|
||||
font-size: calc(var(--mainFontSize) * .8);
|
||||
font-weight: bold;
|
||||
#rm_print_characters_pagination {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 5px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#rm_print_characters_block {
|
||||
/* padding: 5px 0; */
|
||||
overflow-y: auto;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
/* row-gap: 5px; */
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body.charListGrid #rm_print_characters_block {
|
||||
@ -1501,6 +1501,7 @@ select option:not(:checked) {
|
||||
display: flex;
|
||||
overflow-y: auto;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#rm_characters_block .right_menu_button {
|
||||
@ -2216,7 +2217,7 @@ grammarly-extension {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
#kobold_order {
|
||||
.prompt_order {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@ -2226,7 +2227,7 @@ grammarly-extension {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#kobold_order>div {
|
||||
.prompt_order>div {
|
||||
padding: 5px;
|
||||
padding-left: 30px;
|
||||
width: 100%;
|
||||
@ -2241,18 +2242,40 @@ grammarly-extension {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
#kobold_order>div:hover {
|
||||
.prompt_order>div>span:first-child {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.prompt_order>div:hover {
|
||||
background-color: var(--grey30a);
|
||||
}
|
||||
|
||||
#kobold_order>div::after {
|
||||
.prompt_order>div::after {
|
||||
content: "☰";
|
||||
left: 8px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.prompt_order .disabled {
|
||||
opacity: 0.5;
|
||||
filter: grayscale(0.5);
|
||||
}
|
||||
|
||||
.prompt_order .toggle_button {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.prompt_order .toggle_button::after {
|
||||
content: '☑';
|
||||
}
|
||||
|
||||
.prompt_order .disabled .toggle_button::after {
|
||||
content: '☐';
|
||||
}
|
||||
|
||||
/* ------ online status indicators and texts. 2 = kobold AI, 3 = Novel AI ----------*/
|
||||
#online_status2,
|
||||
#online_status_horde,
|
||||
@ -3211,6 +3234,12 @@ h5 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.group_pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#rm_group_chats_block .tag.filterByGroups {
|
||||
display: none;
|
||||
}
|
||||
@ -4568,6 +4597,41 @@ toolcool-color-picker {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.novelai_logit_bias_form {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
column-gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.novelai_logit_bias_text,
|
||||
.novelai_logit_bias_value {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.novelai_logit_bias_list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.novelai_logit_bias_list:empty {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.novelai_logit_bias_list:empty::before {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
content: "No items";
|
||||
font-weight: bolder;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.8;
|
||||
min-height: 2.5rem;
|
||||
}
|
||||
|
||||
/*used to fix smallness of certain FontAwesome glyph which break button squareness*/
|
||||
/*currently used on: CharList Import*/
|
||||
|
||||
@ -5559,3 +5623,77 @@ body.waifuMode .zoomed_avatar {
|
||||
vertical-align: middle;
|
||||
/* To align with adjacent text */
|
||||
}
|
||||
|
||||
.paginationjs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
/* Pagination */
|
||||
.paginationsjs-pages {
|
||||
margin: 0.5em 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.paginationjs-pages ul {
|
||||
list-style-type: none;
|
||||
margin: 0.25em;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.paginationjs-size-changer select {
|
||||
width: unset;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.paginationjs-pages ul li a {
|
||||
padding: 0.05em 0.5em;
|
||||
text-decoration: none;
|
||||
color: var(--SmartThemeBodyColor);
|
||||
border: 1px solid var(--white30a);
|
||||
border-radius: 5px;
|
||||
transition: opacity 0.2s;
|
||||
opacity: 0.8;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.paginationjs-pages ul li a:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.paginationjs-pages ul li.active a {
|
||||
color: var(--SmartThemeQuoteColor);
|
||||
border-color: var(--SmartThemeQuoteColor);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.paginationjs-pages ul li.disabled a {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.paginationjs-nav {
|
||||
padding: 5px;
|
||||
font-size: calc(var(--mainFontSize) * .8);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#select_chat_search {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: white;
|
||||
display: inline-block; /* Change display to inline-block */
|
||||
vertical-align: middle; /* Align to middle if there's a height discrepancy */
|
||||
width: 200px;
|
||||
font-size: 16px;
|
||||
z-index: 10;
|
||||
margin-left: 10px; /* Give some space between the button and search box */
|
||||
}
|
161
server.js
161
server.js
@ -68,6 +68,7 @@ app.use(compression());
|
||||
app.use(responseTime());
|
||||
|
||||
const fs = require('fs');
|
||||
const writeFileAtomicSync = require('write-file-atomic').sync;
|
||||
const readline = require('readline');
|
||||
const open = require('open');
|
||||
|
||||
@ -551,6 +552,7 @@ app.post("/generate", jsonParser, async function (request, response_generate = r
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log("Endpoint response:", data);
|
||||
return response_generate.send(data);
|
||||
}
|
||||
} catch (error) {
|
||||
@ -600,18 +602,14 @@ app.post("/generate_textgenerationwebui", jsonParser, async function (request, r
|
||||
const websocket = new WebSocket(streamingUrl);
|
||||
|
||||
websocket.on('open', async function () {
|
||||
console.log('websocket open');
|
||||
websocket.send(JSON.stringify(request.body));
|
||||
});
|
||||
|
||||
websocket.on('error', (err) => {
|
||||
console.error(err);
|
||||
websocket.close();
|
||||
console.log('WebSocket opened');
|
||||
const combined_args = Object.assign(request.body.use_mancer ? get_mancer_headers() : {}, request.body);
|
||||
websocket.send(JSON.stringify(combined_args));
|
||||
});
|
||||
|
||||
websocket.on('close', (code, buffer) => {
|
||||
const reason = new TextDecoder().decode(buffer)
|
||||
console.log(reason);
|
||||
console.log("WebSocket closed (reason: %o)", reason);
|
||||
});
|
||||
|
||||
while (true) {
|
||||
@ -620,8 +618,27 @@ app.post("/generate_textgenerationwebui", jsonParser, async function (request, r
|
||||
websocket.close();
|
||||
return;
|
||||
}
|
||||
|
||||
let rawMessage = null;
|
||||
try {
|
||||
// This lunacy is because the websocket can fail to connect AFTER we're awaiting 'message'... so 'message' never triggers.
|
||||
// So instead we need to look for 'error' at the same time to reject the promise. And then remove the listener if we resolve.
|
||||
// This is awful.
|
||||
// Welcome to the shenanigan shack.
|
||||
rawMessage = await new Promise(function (resolve, reject) {
|
||||
websocket.once('error', reject);
|
||||
websocket.once('message', (data, isBinary) => {
|
||||
websocket.removeListener('error', reject);
|
||||
resolve(data, isBinary);
|
||||
});
|
||||
});
|
||||
} catch(err) {
|
||||
console.error("Socket error:", err);
|
||||
websocket.close();
|
||||
yield "[SillyTavern] Streaming failed:\n" + err;
|
||||
return;
|
||||
}
|
||||
|
||||
const rawMessage = await new Promise(resolve => websocket.once('message', resolve));
|
||||
const message = json5.parse(rawMessage);
|
||||
|
||||
switch (message.event) {
|
||||
@ -672,11 +689,11 @@ app.post("/generate_textgenerationwebui", jsonParser, async function (request, r
|
||||
|
||||
try {
|
||||
const data = await postAsync(api_server + "/v1/generate", args);
|
||||
console.log(data);
|
||||
console.log("Endpoint response:", data);
|
||||
return response_generate.send(data);
|
||||
} catch (error) {
|
||||
retval = { error: true, status: error.status, response: error.statusText };
|
||||
console.log(error);
|
||||
console.log("Endpoint error:", error);
|
||||
try {
|
||||
retval.response = await error.json();
|
||||
retval.response = retval.response.result;
|
||||
@ -692,7 +709,7 @@ app.post("/savechat", jsonParser, function (request, response) {
|
||||
var dir_name = String(request.body.avatar_url).replace('.png', '');
|
||||
let chat_data = request.body.chat;
|
||||
let jsonlData = chat_data.map(JSON.stringify).join('\n');
|
||||
fs.writeFileSync(`${chatsPath + sanitize(dir_name)}/${sanitize(String(request.body.file_name))}.jsonl`, jsonlData, 'utf8');
|
||||
writeFileAtomicSync(`${chatsPath + sanitize(dir_name)}/${sanitize(String(request.body.file_name))}.jsonl`, jsonlData, 'utf8');
|
||||
return response.send({ result: "ok" });
|
||||
} catch (error) {
|
||||
response.send(error);
|
||||
@ -1217,7 +1234,7 @@ async function charaWrite(img_url, data, target_img, response = undefined, mes =
|
||||
chunks.splice(-1, 0, PNGtext.encode('chara', base64EncodedData));
|
||||
//chunks.splice(-1, 0, text.encode('lorem', 'ipsum'));
|
||||
|
||||
fs.writeFileSync(charactersPath + target_img + '.png', new Buffer.from(encode(chunks)));
|
||||
writeFileAtomicSync(charactersPath + target_img + '.png', new Buffer.from(encode(chunks)));
|
||||
if (response !== undefined) response.send(mes);
|
||||
return true;
|
||||
} catch (err) {
|
||||
@ -1428,18 +1445,16 @@ app.post('/deleteuseravatar', jsonParser, function (request, response) {
|
||||
});
|
||||
|
||||
app.post("/setbackground", jsonParser, function (request, response) {
|
||||
var bg = "#bg1 {background-image: url('../backgrounds/" + request.body.bg + "');}";
|
||||
fs.writeFile('public/css/bg_load.css', bg, 'utf8', function (err) {
|
||||
if (err) {
|
||||
response.send(err);
|
||||
return console.log(err);
|
||||
} else {
|
||||
//response.redirect("/");
|
||||
response.send({ result: 'ok' });
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const bg = `#bg1 {background-image: url('../backgrounds/${request.body.bg}');}`;
|
||||
writeFileAtomicSync('public/css/bg_load.css', bg, 'utf8');
|
||||
response.send({ result: 'ok' });
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
response.send(err);
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/delbackground", jsonParser, function (request, response) {
|
||||
if (!request.body) return response.sendStatus(400);
|
||||
|
||||
@ -1530,25 +1545,13 @@ app.post("/downloadbackground", urlencodedParser, function (request, response) {
|
||||
});
|
||||
|
||||
app.post("/savesettings", jsonParser, function (request, response) {
|
||||
fs.writeFile('public/settings.json', JSON.stringify(request.body, null, 4), 'utf8', function (err) {
|
||||
if (err) {
|
||||
response.send(err);
|
||||
console.log(err);
|
||||
} else {
|
||||
response.send({ result: "ok" });
|
||||
}
|
||||
});
|
||||
|
||||
/*fs.writeFile('public/settings.json', JSON.stringify(request.body), 'utf8', function (err) {
|
||||
if (err) {
|
||||
response.send(err);
|
||||
return console.log(err);
|
||||
//response.send(err);
|
||||
} else {
|
||||
//response.redirect("/");
|
||||
response.send({ result: "ok" });
|
||||
}
|
||||
});*/
|
||||
try {
|
||||
writeFileAtomicSync('public/settings.json', JSON.stringify(request.body, null, 4), 'utf8');
|
||||
response.send({ result: "ok" });
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
response.send(err);
|
||||
}
|
||||
});
|
||||
|
||||
function getCharaCardV2(jsonObject) {
|
||||
@ -1714,7 +1717,7 @@ app.post('/savetheme', jsonParser, (request, response) => {
|
||||
}
|
||||
|
||||
const filename = path.join(directories.themes, sanitize(request.body.name) + '.json');
|
||||
fs.writeFileSync(filename, JSON.stringify(request.body, null, 4), 'utf8');
|
||||
writeFileAtomicSync(filename, JSON.stringify(request.body, null, 4), 'utf8');
|
||||
|
||||
return response.sendStatus(200);
|
||||
});
|
||||
@ -1725,7 +1728,7 @@ app.post('/savemovingui', jsonParser, (request, response) => {
|
||||
}
|
||||
|
||||
const filename = path.join(directories.movingUI, sanitize(request.body.name) + '.json');
|
||||
fs.writeFileSync(filename, JSON.stringify(request.body, null, 4), 'utf8');
|
||||
writeFileAtomicSync(filename, JSON.stringify(request.body, null, 4), 'utf8');
|
||||
|
||||
return response.sendStatus(200);
|
||||
});
|
||||
@ -1736,7 +1739,7 @@ app.post('/savequickreply', jsonParser, (request, response) => {
|
||||
}
|
||||
|
||||
const filename = path.join(directories.quickreplies, sanitize(request.body.name) + '.json');
|
||||
fs.writeFileSync(filename, JSON.stringify(request.body, null, 4), 'utf8');
|
||||
writeFileAtomicSync(filename, JSON.stringify(request.body, null, 4), 'utf8');
|
||||
|
||||
return response.sendStatus(200);
|
||||
});
|
||||
@ -1853,7 +1856,7 @@ app.post("/generate_novelai", jsonParser, async function (request, response_gene
|
||||
const novelai = require('./src/novelai');
|
||||
const isNewModel = (request.body.model.includes('clio') || request.body.model.includes('kayra'));
|
||||
const isKrake = request.body.model.includes('krake');
|
||||
const badWordsList = isNewModel ? novelai.badWordsList : (isKrake ? novelai.krakeBadWordsList : novelai.euterpeBadWordsList);
|
||||
const badWordsList = (isNewModel ? novelai.badWordsList : (isKrake ? novelai.krakeBadWordsList : novelai.euterpeBadWordsList)).slice();
|
||||
|
||||
// Add customized bad words for Clio and Kayra
|
||||
if (isNewModel && Array.isArray(request.body.bad_words_ids)) {
|
||||
@ -1864,6 +1867,13 @@ app.post("/generate_novelai", jsonParser, async function (request, response_gene
|
||||
}
|
||||
}
|
||||
|
||||
// Add default biases for dinkus and asterism
|
||||
const logit_bias_exp = isNewModel ? novelai.logitBiasExp.slice() : null;
|
||||
|
||||
if (Array.isArray(logit_bias_exp) && Array.isArray(request.body.logit_bias_exp)) {
|
||||
logit_bias_exp.push(...request.body.logit_bias_exp);
|
||||
}
|
||||
|
||||
const data = {
|
||||
"input": request.body.input,
|
||||
"model": request.body.model,
|
||||
@ -1883,16 +1893,14 @@ app.post("/generate_novelai", jsonParser, async function (request, response_gene
|
||||
"top_p": request.body.top_p,
|
||||
"top_k": request.body.top_k,
|
||||
"typical_p": request.body.typical_p,
|
||||
"top_g": request.body.top_g,
|
||||
"mirostat_lr": request.body.mirostat_lr,
|
||||
"mirostat_tau": request.body.mirostat_tau,
|
||||
"cfg_scale": request.body.cfg_scale,
|
||||
"cfg_uc": request.body.cfg_uc,
|
||||
"phrase_rep_pen": request.body.phrase_rep_pen,
|
||||
"stop_sequences": request.body.stop_sequences,
|
||||
//"stop_sequences": {{187}},
|
||||
"bad_words_ids": badWordsList,
|
||||
"logit_bias_exp": isNewModel ? novelai.logitBiasExp : null,
|
||||
"logit_bias_exp": logit_bias_exp,
|
||||
//generate_until_sentence = true;
|
||||
"use_cache": request.body.use_cache,
|
||||
"use_string": true,
|
||||
@ -2325,7 +2333,7 @@ app.post("/exportcharacter", jsonParser, async function (request, response) {
|
||||
},
|
||||
};
|
||||
const exifString = exif.dump(metadata);
|
||||
fs.writeFileSync(metadataPath, exifString, 'binary');
|
||||
writeFileAtomicSync(metadataPath, exifString, 'binary');
|
||||
|
||||
await webp.cwebp(filename, inputWebpPath, '-q 95');
|
||||
await webp.webpmux_add(inputWebpPath, outputWebpPath, metadataPath, 'exif');
|
||||
@ -2407,13 +2415,17 @@ app.post("/importchat", urlencodedParser, function (request, response) {
|
||||
});
|
||||
|
||||
const errors = [];
|
||||
newChats.forEach(chat => fs.writeFile(
|
||||
`${chatsPath + avatar_url}/${ch_name} - ${humanizedISO8601DateTime()} imported.jsonl`,
|
||||
chat.map(JSON.stringify).join('\n'),
|
||||
'utf8',
|
||||
(err) => err ?? errors.push(err)
|
||||
)
|
||||
);
|
||||
|
||||
for (const chat of newChats) {
|
||||
const filePath = `${chatsPath + avatar_url}/${ch_name} - ${humanizedISO8601DateTime()} imported.jsonl`;
|
||||
const fileContent = chat.map(tryParse).filter(x => x).join('\n');
|
||||
|
||||
try {
|
||||
writeFileAtomicSync(filePath, fileContent, 'utf8');
|
||||
} catch (err) {
|
||||
errors.push(err);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 < errors.length) {
|
||||
response.send('Errors occurred while writing character files. Errors: ' + JSON.stringify(errors));
|
||||
@ -2451,7 +2463,7 @@ app.post("/importchat", urlencodedParser, function (request, response) {
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(`${chatsPath + avatar_url}/${ch_name} - ${humanizedISO8601DateTime()} imported.jsonl`, chat.map(JSON.stringify).join('\n'), 'utf8');
|
||||
writeFileAtomicSync(`${chatsPath + avatar_url}/${ch_name} - ${humanizedISO8601DateTime()} imported.jsonl`, chat.map(JSON.stringify).join('\n'), 'utf8');
|
||||
|
||||
response.send({ res: true });
|
||||
} else {
|
||||
@ -2520,7 +2532,7 @@ app.post('/importworldinfo', urlencodedParser, (request, response) => {
|
||||
return response.status(400).send('World file must have a name');
|
||||
}
|
||||
|
||||
fs.writeFileSync(pathToNewFile, fileContents);
|
||||
writeFileAtomicSync(pathToNewFile, fileContents);
|
||||
return response.send({ name: worldName });
|
||||
});
|
||||
|
||||
@ -2544,7 +2556,7 @@ app.post('/editworldinfo', jsonParser, (request, response) => {
|
||||
const filename = `${sanitize(request.body.name)}.json`;
|
||||
const pathToFile = path.join(directories.worlds, filename);
|
||||
|
||||
fs.writeFileSync(pathToFile, JSON.stringify(request.body.data, null, 4));
|
||||
writeFileAtomicSync(pathToFile, JSON.stringify(request.body.data, null, 4));
|
||||
|
||||
return response.send({ ok: true });
|
||||
});
|
||||
@ -2565,7 +2577,7 @@ app.post('/uploaduseravatar', urlencodedParser, async (request, response) => {
|
||||
|
||||
const filename = request.body.overwrite_name || `${Date.now()}.png`;
|
||||
const pathToNewFile = path.join(directories.avatars, filename);
|
||||
fs.writeFileSync(pathToNewFile, image);
|
||||
writeFileAtomicSync(pathToNewFile, image);
|
||||
fs.rmSync(pathToUpload);
|
||||
return response.send({ path: filename });
|
||||
} catch (err) {
|
||||
@ -2642,7 +2654,7 @@ app.post('/creategroup', jsonParser, (request, response) => {
|
||||
fs.mkdirSync(directories.groups);
|
||||
}
|
||||
|
||||
fs.writeFileSync(pathToFile, fileData);
|
||||
writeFileAtomicSync(pathToFile, fileData);
|
||||
return response.send(groupMetadata);
|
||||
});
|
||||
|
||||
@ -2654,7 +2666,7 @@ app.post('/editgroup', jsonParser, (request, response) => {
|
||||
const pathToFile = path.join(directories.groups, `${id}.json`);
|
||||
const fileData = JSON.stringify(request.body);
|
||||
|
||||
fs.writeFileSync(pathToFile, fileData);
|
||||
writeFileAtomicSync(pathToFile, fileData);
|
||||
return response.send({ ok: true });
|
||||
});
|
||||
|
||||
@ -2708,7 +2720,7 @@ app.post('/savegroupchat', jsonParser, (request, response) => {
|
||||
|
||||
let chat_data = request.body.chat;
|
||||
let jsonlData = chat_data.map(JSON.stringify).join('\n');
|
||||
fs.writeFileSync(pathToFile, jsonlData, 'utf8');
|
||||
writeFileAtomicSync(pathToFile, jsonlData, 'utf8');
|
||||
return response.send({ ok: true });
|
||||
});
|
||||
|
||||
@ -2907,7 +2919,7 @@ async function generateThumbnail(type, file) {
|
||||
buffer = fs.readFileSync(pathToOriginalFile);
|
||||
}
|
||||
|
||||
fs.writeFileSync(pathToCachedFile, buffer);
|
||||
writeFileAtomicSync(pathToCachedFile, buffer);
|
||||
}
|
||||
catch (outer) {
|
||||
return null;
|
||||
@ -3468,7 +3480,7 @@ app.post("/save_preset", jsonParser, function (request, response) {
|
||||
}
|
||||
|
||||
const fullpath = path.join(directory, filename);
|
||||
fs.writeFileSync(fullpath, JSON.stringify(request.body.preset, null, 4), 'utf-8');
|
||||
writeFileAtomicSync(fullpath, JSON.stringify(request.body.preset, null, 4), 'utf-8');
|
||||
return response.send({ name });
|
||||
});
|
||||
|
||||
@ -3503,7 +3515,7 @@ app.post("/savepreset_openai", jsonParser, function (request, response) {
|
||||
|
||||
const filename = `${name}.settings`;
|
||||
const fullpath = path.join(directories.openAI_Settings, filename);
|
||||
fs.writeFileSync(fullpath, JSON.stringify(request.body, null, 4), 'utf-8');
|
||||
writeFileAtomicSync(fullpath, JSON.stringify(request.body, null, 4), 'utf-8');
|
||||
return response.send({ name });
|
||||
});
|
||||
|
||||
@ -3637,7 +3649,8 @@ const setupTasks = async function () {
|
||||
console.log('Launching...');
|
||||
|
||||
if (autorun) open(autorunUrl.toString());
|
||||
console.log('SillyTavern is listening on: ' + tavernUrl);
|
||||
|
||||
console.log('\x1b[32mSillyTavern is listening on: ' + tavernUrl + '\x1b[0m');
|
||||
|
||||
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');
|
||||
@ -3805,7 +3818,7 @@ function migrateSecrets() {
|
||||
if (modified) {
|
||||
console.log('Writing updated settings.json...');
|
||||
const settingsContent = JSON.stringify(settings);
|
||||
fs.writeFileSync(SETTINGS_FILE, settingsContent, "utf-8");
|
||||
writeFileAtomicSync(SETTINGS_FILE, settingsContent, "utf-8");
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
@ -4176,7 +4189,7 @@ app.post('/upload_sprite_pack', urlencodedParser, async (request, response) => {
|
||||
|
||||
// Write sprite buffer to disk
|
||||
const pathToSprite = path.join(spritesPath, filename);
|
||||
fs.writeFileSync(pathToSprite, buffer);
|
||||
writeFileAtomicSync(pathToSprite, buffer);
|
||||
}
|
||||
|
||||
// Remove uploaded ZIP file
|
||||
@ -4401,7 +4414,7 @@ function importRisuSprites(data) {
|
||||
|
||||
const filename = label + '.png';
|
||||
const pathToFile = path.join(spritesPath, filename);
|
||||
fs.writeFileSync(pathToFile, fileBase64, { encoding: 'base64' });
|
||||
writeFileAtomicSync(pathToFile, fileBase64, { encoding: 'base64' });
|
||||
}
|
||||
|
||||
// Remove additionalAssets and emotions from data (they are now in the sprites folder)
|
||||
@ -4415,13 +4428,13 @@ function importRisuSprites(data) {
|
||||
function writeSecret(key, value) {
|
||||
if (!fs.existsSync(SECRETS_FILE)) {
|
||||
const emptyFile = JSON.stringify({});
|
||||
fs.writeFileSync(SECRETS_FILE, emptyFile, "utf-8");
|
||||
writeFileAtomicSync(SECRETS_FILE, emptyFile, "utf-8");
|
||||
}
|
||||
|
||||
const fileContents = fs.readFileSync(SECRETS_FILE);
|
||||
const secrets = JSON.parse(fileContents);
|
||||
secrets[key] = value;
|
||||
fs.writeFileSync(SECRETS_FILE, JSON.stringify(secrets), "utf-8");
|
||||
writeFileAtomicSync(SECRETS_FILE, JSON.stringify(secrets), "utf-8");
|
||||
}
|
||||
|
||||
function readSecret(key) {
|
||||
|
@ -9,7 +9,8 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const util = require("util");
|
||||
const writeFile = util.promisify(fs.writeFile);
|
||||
const writeFileAtomic = require("write-file-atomic");
|
||||
const writeFile = util.promisify(writeFileAtomic);
|
||||
const readFile = util.promisify(fs.readFile);
|
||||
const readdir = util.promisify(fs.readdir);
|
||||
const crypto = require("crypto");
|
||||
|
Loading…
x
Reference in New Issue
Block a user