mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge branch 'dev'
This commit is contained in:
@@ -3,7 +3,8 @@ const port = 8000;
|
||||
const whitelist = ['127.0.0.1']; //Example for add several IP in whitelist: ['127.0.0.1', '192.168.0.10']
|
||||
const whitelistMode = false; //Disabling enabling the ip whitelist mode. true/false
|
||||
const autorun = true; //Autorun in the browser. true/false
|
||||
const enableExtensions = true; //Enables support for TavernAI-extras project
|
||||
|
||||
module.exports = {
|
||||
port, whitelist, whitelistMode, autorun
|
||||
port, whitelist, whitelistMode, autorun, enableExtensions,
|
||||
};
|
||||
|
1
public/img/minus-solid.svg
Normal file
1
public/img/minus-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M416 256c0 17.7-14.3 32-32 32L32 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z"/></svg>
|
After Width: | Height: | Size: 348 B |
1
public/img/plus-solid.svg
Normal file
1
public/img/plus-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M240 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H32c-17.7 0-32 14.3-32 32s14.3 32 32 32H176V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H240V80z"/></svg>
|
After Width: | Height: | Size: 429 B |
1
public/img/user-group-solid.svg
Normal file
1
public/img/user-group-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M96 128a128 128 0 1 1 256 0A128 128 0 1 1 96 128zM0 482.3C0 383.8 79.8 304 178.3 304h91.4C368.2 304 448 383.8 448 482.3c0 16.4-13.3 29.7-29.7 29.7H29.7C13.3 512 0 498.7 0 482.3zM609.3 512H471.4c5.4-9.4 8.6-20.3 8.6-32v-8c0-60.7-27.1-115.2-69.8-151.8c2.4-.1 4.7-.2 7.1-.2h61.4C567.8 320 640 392.2 640 481.3c0 17-13.8 30.7-30.7 30.7zM432 256c-31 0-59-12.6-79.3-32.9C372.4 196.5 384 163.6 384 128c0-26.8-6.6-52.1-18.3-74.3C384.3 40.1 407.2 32 432 32c61.9 0 112 50.1 112 112s-50.1 112-112 112z"/></svg>
|
After Width: | Height: | Size: 737 B |
1304
public/index.html
1304
public/index.html
File diff suppressed because it is too large
Load Diff
217
public/scripts/extensions.js
Normal file
217
public/scripts/extensions.js
Normal file
@@ -0,0 +1,217 @@
|
||||
|
||||
const extensions_urlKey = 'extensions_url';
|
||||
const extensions_autoConnectKey = 'extensions_autoconnect';
|
||||
let extensions = [];
|
||||
|
||||
(function () {
|
||||
const settings_html = `
|
||||
<div class="extensions_block">
|
||||
<hr>
|
||||
<h3>Extensions: <a target="_blank" href="https://github.com/SillyLossy/TavernAI-extras">TavernAI-extras</a></h3>
|
||||
<input id="extensions_url" type="text" class="text_pole" />
|
||||
<div class="extensions_url_block">
|
||||
<input id="extensions_connect" class="menu_button" type="submit" value="Connect" />
|
||||
<span class="expander"></span>
|
||||
<label for="extensions_autoconnect"><input id="extensions_autoconnect" type="checkbox"/>Auto-connect</label>
|
||||
</div>
|
||||
<div id="extensions_status">Not connected</div>
|
||||
<div id="extensions_loaded">
|
||||
<h4>Active extensions</h4>
|
||||
<ul id="extensions_list">
|
||||
</ul>
|
||||
</div>
|
||||
<div id="extensions_settings">
|
||||
<h3>Extension settings</h3>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const settings_style = `
|
||||
<style>
|
||||
#extensions_url {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#extensions_loaded {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#extensions_status {
|
||||
margin-bottom: 10px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.extensions_block input[type="submit"]:hover{
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.extensions_block input[type="checkbox"] {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
label[for="extensions_autoconnect"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.extensions_url_block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.extensions_url_block h4 {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.extensions_block {
|
||||
clear: both;
|
||||
padding: 0.05px; /* clear fix */
|
||||
}
|
||||
|
||||
.success {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.failure {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.expander {
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
|
||||
const defaultUrl = "http://localhost:5100";
|
||||
let connectedToApi = false;
|
||||
|
||||
async function connectClickHandler() {
|
||||
const baseUrl = $("#extensions_url").val();
|
||||
localStorage.setItem(extensions_urlKey, baseUrl);
|
||||
await connectToApi(baseUrl);
|
||||
}
|
||||
|
||||
function autoConnectInputHandler() {
|
||||
const value = $(this).prop('checked');
|
||||
localStorage.setItem(extensions_autoConnectKey, value.toString());
|
||||
|
||||
if (value && !connectedToApi) {
|
||||
$("#extensions_connect").trigger('click');
|
||||
}
|
||||
}
|
||||
|
||||
async function connectToApi(baseUrl) {
|
||||
const url = new URL(baseUrl);
|
||||
url.pathname = '/api/extensions';
|
||||
|
||||
try {
|
||||
const getExtensionsResult = await fetch(url, { method: 'GET', headers: { 'Bypass-Tunnel-Reminder': 'bypass' } });
|
||||
|
||||
if (getExtensionsResult.ok) {
|
||||
const data = await getExtensionsResult.json();
|
||||
extensions = data.extensions;
|
||||
applyExtensions(baseUrl);
|
||||
}
|
||||
|
||||
updateStatus(getExtensionsResult.ok);
|
||||
}
|
||||
catch {
|
||||
updateStatus(false);
|
||||
}
|
||||
}
|
||||
|
||||
function updateStatus(success) {
|
||||
connectedToApi = success;
|
||||
const _text = success ? 'Connected to API' : 'Could not connect to API';
|
||||
const _class = success ? 'success' : 'failure';
|
||||
$('#extensions_status').text(_text);
|
||||
$('#extensions_status').attr('class', _class);
|
||||
|
||||
if (success && extensions.length) {
|
||||
$('#extensions_loaded').show(200);
|
||||
$('#extensions_settings').show(200);
|
||||
$('#extensions_list').empty();
|
||||
|
||||
for (let extension of extensions) {
|
||||
$('#extensions_list').append(`<li id="${extension.name}">${extension.metadata.display_name}</li>`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$('#extensions_loaded').hide(200);
|
||||
$('#extensions_settings').hide(200);
|
||||
$('#extensions_list').empty();
|
||||
}
|
||||
}
|
||||
|
||||
function applyExtensions(baseUrl) {
|
||||
const url = new URL(baseUrl);
|
||||
|
||||
if (!Array.isArray(extensions) || extensions.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let extension of extensions) {
|
||||
addExtensionStyle(extension);
|
||||
addExtensionScript(extension);
|
||||
}
|
||||
|
||||
async function addExtensionStyle(extension) {
|
||||
if (extension.metadata.css) {
|
||||
try {
|
||||
url.pathname = `/api/style/${extension.name}`;
|
||||
const link = url.toString();
|
||||
|
||||
const result = await fetch(link, { method: 'GET', headers: { 'Bypass-Tunnel-Reminder': 'bypass' } });
|
||||
const text = await result.text();
|
||||
|
||||
if ($(`style[id="${link}"]`).length === 0) {
|
||||
const style = document.createElement('style');
|
||||
style.id = link;
|
||||
style.innerHTML = text;
|
||||
$('head').append(style);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function addExtensionScript(extension) {
|
||||
if (extension.metadata.js) {
|
||||
try {
|
||||
url.pathname = `/api/script/${extension.name}`;
|
||||
const link = url.toString();
|
||||
|
||||
const result = await fetch(link, { method: 'GET', headers: { 'Bypass-Tunnel-Reminder': 'bypass' } });
|
||||
const text = await result.text();
|
||||
|
||||
if ($(`script[id="${link}"]`).length === 0) {
|
||||
const script = document.createElement('script');
|
||||
script.id = link;
|
||||
script.type = 'module';
|
||||
script.innerHTML = text;
|
||||
$('body').append(script);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(async function () {
|
||||
const url = localStorage.getItem(extensions_urlKey) ?? defaultUrl;
|
||||
const autoConnect = localStorage.getItem(extensions_autoConnectKey) == 'true';
|
||||
$('#rm_api_block').append(settings_html);
|
||||
$('head').append(settings_style);
|
||||
$("#extensions_url").val(url);
|
||||
$("#extensions_connect").on('click', connectClickHandler);
|
||||
$("#extensions_autoconnect").on('input', autoConnectInputHandler);
|
||||
$("#extensions_autoconnect").prop('checked', autoConnect).trigger('input');
|
||||
});
|
||||
})();
|
@@ -5,20 +5,20 @@ GPT-2/3 byte pair encoder/decoder/tokenizer based on [@latitudegames/GPT-3-Encod
|
||||
See also: [JS byte pair encoder for OpenAI's CLIP model](https://github.com/josephrocca/clip-bpe-js).
|
||||
|
||||
```js
|
||||
import {encode, decode} from "https://deno.land/x/gpt_2_3_tokenizer@v0.0.1/mod.js";
|
||||
import {encode, decode} from "https://deno.land/x/gpt_2_3_tokenizer@v0.0.2/mod.js";
|
||||
let text = "hello world";
|
||||
console.log(encode(text)); // [258, 18798, 995]
|
||||
console.log(decode(encode(text))); // "hello world"
|
||||
```
|
||||
or:
|
||||
```js
|
||||
let mod = await import("https://deno.land/x/gpt_2_3_tokenizer@v0.0.1/mod.js");
|
||||
let mod = await import("https://deno.land/x/gpt_2_3_tokenizer@v0.0.2/mod.js");
|
||||
mod.encode("hello world"); // [258, 18798, 995]
|
||||
```
|
||||
or to include it as a global variable in the browser:
|
||||
```html
|
||||
<script type=module>
|
||||
import tokenizer from "https://deno.land/x/gpt_2_3_tokenizer@v0.0.1/mod.js";
|
||||
import tokenizer from "https://deno.land/x/gpt_2_3_tokenizer@v0.0.2/mod.js";
|
||||
window.tokenizer = tokenizer;
|
||||
</script>
|
||||
```
|
||||
|
@@ -81,7 +81,7 @@ const bpe_ranks = dictZip(bpe_merges, range(0, bpe_merges.length))
|
||||
const cache = {}
|
||||
|
||||
function bpe(token) {
|
||||
if (token in cache) {
|
||||
if (Object.hasOwn(cache, token)) {
|
||||
return cache[token]
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ function bpe(token) {
|
||||
}
|
||||
))]
|
||||
|
||||
if (!(bigram in bpe_ranks)) {
|
||||
if (!(Object.hasOwn(bpe_ranks, bigram))) {
|
||||
break
|
||||
}
|
||||
|
||||
|
2008
public/scripts/popper.js
Normal file
2008
public/scripts/popper.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
{"username":"You","api_server":"http://localhost:5000/api","preset_settings":"gui","preset_settings_novel":"Classic-Euterpe","user_avatar":"legat.png","temp":0.43,"amount_gen":90,"max_context":2048,"anchor_order":0,"style_anchor":false,"character_anchor":true,"main_api":"kobold","api_key_novel":"","rep_pen":1.17,"rep_pen_size":1024,"model_novel":"euterpe-v2","temp_novel":1.11,"rep_pen_novel":1.11,"rep_pen_size_novel":320}
|
||||
{"username":"You","api_server":"http://localhost:5000/api","api_server_textgenerationwebui":"http://127.0.0.1:7860","preset_settings":"gui","preset_settings_novel":"Classic-Euterpe","user_avatar":"legat.png","temp":0.43,"amount_gen":90,"max_context":2048,"anchor_order":0,"style_anchor":false,"character_anchor":true,"auto_connect":false,"auto_load_chat":false,"main_api":"kobold","api_key_novel":"","rep_pen":1.17,"rep_pen_size":1024,"model_novel":"euterpe-v2","temp_novel":1.11,"rep_pen_novel":1.11,"rep_pen_size_novel":320,"world_info":null,"world_info_depth":2,"world_info_budget":200,"textgenerationwebui_settings":{"temp":0.5,"top_p":0.9,"top_k":0,"typical_p":1,"rep_pen":1.1,"rep_pen_size":0,"penalty_alpha":0}}
|
412
public/style.css
412
public/style.css
@@ -631,17 +631,26 @@ select option:not(:checked) { /* works to color unselected items */
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#api_url_text{
|
||||
.oobabooga_logo {
|
||||
margin: 5px auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#api_url_text, #textgenerationwebui_api_url_text{
|
||||
/*margin-right: 4px;*/
|
||||
display:block;
|
||||
}
|
||||
#api_button, #api_button_novel {
|
||||
#api_button, #api_button_novel, #api_button_textgenerationwebui {
|
||||
|
||||
}
|
||||
|
||||
#textgenerationwebui_api pre {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#api_button:hover, #api_button_novel:hover{background-color:green;}
|
||||
|
||||
#api_loading{
|
||||
#api_loading, #api_loading_textgenerationwebui{
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
display: none;
|
||||
@@ -659,6 +668,10 @@ select option:not(:checked) { /* works to color unselected items */
|
||||
/* visibility: hidden; */
|
||||
}
|
||||
|
||||
#rm_characters_block .right_menu_button {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
#rm_characters_topbar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -677,16 +690,22 @@ select option:not(:checked) { /* works to color unselected items */
|
||||
}
|
||||
|
||||
#form_character_search_form {
|
||||
margin-bottom: 1rem;
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
#character_search_bar {
|
||||
flex: 1;
|
||||
font-size: 1em;
|
||||
padding-left: 0.75em;
|
||||
margin-left: 0;
|
||||
margin-right: 0.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#character_search_bar::-webkit-search-cancel-button {
|
||||
input[type=search]::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
@@ -699,7 +718,7 @@ select option:not(:checked) { /* works to color unselected items */
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#character_search_bar:focus::-webkit-search-cancel-button {
|
||||
input[type=search]:focus::-webkit-search-cancel-button {
|
||||
opacity: .3;
|
||||
pointer-events: all;
|
||||
}
|
||||
@@ -1068,20 +1087,20 @@ width: 103px;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
#online_status2{
|
||||
#online_status2, #online_status4{
|
||||
opacity: 0.5;
|
||||
margin-top: 2px;
|
||||
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
#online_status_indicator2{
|
||||
#online_status_indicator2, #online_status_indicator4{
|
||||
border-radius: 7px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background-color: red;
|
||||
display: inline-block;
|
||||
}
|
||||
#online_status_text2{
|
||||
#online_status_text2, #online_status_text4{
|
||||
margin-left: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -1109,7 +1128,7 @@ width: 103px;
|
||||
|
||||
/* hidden until we find out a way to handle it better */
|
||||
#softprompt_block {
|
||||
display: none !important;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#world_info {
|
||||
@@ -1294,7 +1313,6 @@ width: 103px;
|
||||
}
|
||||
|
||||
.world_entry_form_control input[type=button] {
|
||||
opacity: 0.7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -1305,18 +1323,15 @@ width: 103px;
|
||||
.world_entry_form_control .checkbox {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.world_entry_form_control .checkbox h4 {
|
||||
margin-left: 0.5rem;
|
||||
margin-top: 0;
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.world_entry_form_control .checkbox:not(:first-child) {
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.world_entry_form_radios {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
@@ -1615,13 +1630,15 @@ input[type="range"] {
|
||||
background-color: var(--black50a);
|
||||
}
|
||||
#anchor_checkbox, #power-user-option-checkboxes{
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 5px;
|
||||
}
|
||||
#anchor_checkbox label, #power-user-option-checkboxes label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
column-gap: 10px;
|
||||
align-items: center;
|
||||
text-align: left;
|
||||
display: grid;
|
||||
grid-template-rows: 30px auto;
|
||||
grid-template-columns: 30px auto;
|
||||
grid-gap:5px;
|
||||
}
|
||||
|
||||
#shadow_character_popup{
|
||||
@@ -1640,7 +1657,7 @@ input[type="range"] {
|
||||
background-color: var(--black30a);
|
||||
backdrop-filter: blur(50px);
|
||||
-webkit-backdrop-filter: blur(30px);
|
||||
grid-template-rows: 50px 100px 100px auto;
|
||||
grid-template-rows: 50px 100px 100px 100px auto;
|
||||
grid-gap: 10px;
|
||||
max-width: 800px;
|
||||
height: calc(100vh - 50px);
|
||||
@@ -1840,6 +1857,333 @@ border-radius: 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* GROUP CHATS */
|
||||
|
||||
#rm_group_top_bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
#rm_button_group_chats{
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
#rm_button_group_chats h2{
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
font-size: 16px;
|
||||
color: rgb(188, 193, 200, 1);
|
||||
border: 1px solid #333;
|
||||
background-color: rgba(0,0,0,0.3);
|
||||
padding:6px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
#rm_group_chats_block {
|
||||
display: none;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
#rm_group_chat_name {
|
||||
width: 90%;
|
||||
}
|
||||
#rm_group_buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
align-items: flex-end;
|
||||
}
|
||||
#rm_group_buttons .checkbox {
|
||||
display: flex;
|
||||
}
|
||||
#rm_group_buttons .checkbox h4 {
|
||||
display: inline-block;
|
||||
}
|
||||
#rm_group_buttons > input {
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
#rm_group_buttons > input:disabled {
|
||||
filter: brightness(0.3);
|
||||
cursor: unset;
|
||||
}
|
||||
#rm_group_members, #rm_group_add_members {
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
#rm_group_buttons_expander {
|
||||
flex-grow: 1;
|
||||
}
|
||||
#rm_group_delete {
|
||||
color: rgb(190, 0, 0);
|
||||
}
|
||||
#rm_group_members:empty {
|
||||
width: 100%;
|
||||
}
|
||||
#rm_group_members:empty::before {
|
||||
content: 'Group is empty';
|
||||
font-size: 1rem;
|
||||
font-weight: bolder;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0.8;
|
||||
}
|
||||
#rm_group_add_members:empty {
|
||||
width: 100%;
|
||||
}
|
||||
#rm_group_add_members_header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
#rm_group_add_members_header input {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
#rm_group_add_members:empty::before {
|
||||
content: 'No characters available';
|
||||
font-size: 1rem;
|
||||
font-weight: bolder;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.group_member_icon {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin: 0 10px;
|
||||
}
|
||||
.group_member_icon img {
|
||||
filter: invert(1);
|
||||
}
|
||||
.group_member {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
cursor:pointer;
|
||||
}
|
||||
.group_member .ch_name {
|
||||
flex-grow: 1;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.group_member:hover{
|
||||
background-color: #ffffff11;
|
||||
}
|
||||
#group_member_template {
|
||||
display: none !important;
|
||||
}
|
||||
#group_list_template {
|
||||
display: none !important;
|
||||
}
|
||||
.group_select {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.group_select:hover {
|
||||
background-color: #ffffff11;
|
||||
}
|
||||
.group_select .group_icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 0 10px;
|
||||
}
|
||||
.group_select .ch_name {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.group_select .group_icon img {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
#typing_indicator_template {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.typing_indicator {
|
||||
position: sticky;
|
||||
bottom: 10px;
|
||||
margin: 10px;
|
||||
opacity: 0.6;
|
||||
text-shadow: 2px 2px 2px rgba(0,0,0,0.6);
|
||||
}
|
||||
|
||||
.typing_indicator:after {
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
animation: ellipsis steps(4,end) 1500ms infinite;
|
||||
content: ""; /* ascii code for the ellipsis character */
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
@keyframes ellipsis {
|
||||
0% {
|
||||
content: ""
|
||||
}
|
||||
25% {
|
||||
content: "."
|
||||
}
|
||||
50% {
|
||||
content: ".."
|
||||
}
|
||||
75% {
|
||||
content: "..."
|
||||
}
|
||||
}
|
||||
|
||||
#group_avatars_template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.avatar_collage {
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.avatar_collage img {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
border-radius: 0% !important;
|
||||
}
|
||||
|
||||
.collage_2 .img_1 {
|
||||
left: 0;
|
||||
top: 0;
|
||||
max-width: 50%;
|
||||
max-height: 100%;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.collage_2 .img_2 {
|
||||
left: 50%;
|
||||
top: 0;
|
||||
max-width: 50%;
|
||||
max-height: 100%;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.collage_3 .img_1 {
|
||||
left: 0;
|
||||
top: 0;
|
||||
max-width: 50%;
|
||||
max-height: 50%;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.collage_3 .img_2 {
|
||||
left: 50%;
|
||||
top: 0;
|
||||
max-width: 50%;
|
||||
max-height: 50%;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.collage_3 .img_3 {
|
||||
left: 0;
|
||||
top: 50%;
|
||||
max-width: 100%;
|
||||
max-height: 50%;
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.collage_4 .img_1 {
|
||||
left: 0;
|
||||
top: 0;
|
||||
max-width: 50%;
|
||||
max-height: 50%;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.collage_4 .img_2 {
|
||||
left: 50%;
|
||||
top: 0;
|
||||
max-width: 50%;
|
||||
max-height: 50%;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.collage_4 .img_3 {
|
||||
left: 0;
|
||||
top: 50%;
|
||||
max-width: 50%;
|
||||
max-height: 50%;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.collage_4 .img_4 {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
max-width: 50%;
|
||||
max-height: 50%;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
span.warning {
|
||||
color:rgb(190, 0, 0);
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
#talkativeness_hint {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#talkativeness_expander {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
||||
#talkativeness_div input[type="range"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#talkativeness_hint span {
|
||||
min-width: 10em;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
#talkativeness_hint span:nth-child(1) {
|
||||
text-align: left;
|
||||
}
|
||||
#talkativeness_hint span:nth-child(2) {
|
||||
text-align: center;
|
||||
}
|
||||
#talkativeness_hint span:nth-child(3) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* css/style.css */
|
||||
|
||||
p {
|
||||
@@ -1958,4 +2302,22 @@ a {
|
||||
right:0;
|
||||
box-shadow: -5px 0 20px 0 var(--black70a);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
/* Message images */
|
||||
.mes img.img_extra {
|
||||
max-width: 600px;
|
||||
max-height: 300px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.mes img.img_extra ~ * {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.mes img.img_extra {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
199
server.js
199
server.js
@@ -25,16 +25,15 @@ const server_port = config.port;
|
||||
const whitelist = config.whitelist;
|
||||
const whitelistMode = config.whitelistMode;
|
||||
const autorun = config.autorun;
|
||||
|
||||
const enableExtensions = config.enableExtensions;
|
||||
|
||||
|
||||
var Client = require('node-rest-client').Client;
|
||||
var client = new Client();
|
||||
|
||||
var api_server = "";//"http://127.0.0.1:5000";
|
||||
//var server_port = 8000;
|
||||
|
||||
var api_server = "http://0.0.0.0:5000";
|
||||
var api_novelai = "https://api.novelai.net";
|
||||
var main_api = "kobold";
|
||||
|
||||
var response_get_story;
|
||||
var response_generate;
|
||||
@@ -83,7 +82,12 @@ if (is_colab && process.env.googledrive == 2){
|
||||
const jsonParser = express.json({limit: '100mb'});
|
||||
const urlencodedParser = express.urlencoded({extended: true, limit: '100mb'});
|
||||
const baseRequestArgs = { headers: { "Content-Type": "application/json" } };
|
||||
const directories = { worlds: 'public/worlds/', avatars: 'public/User Avatars' };
|
||||
const directories = {
|
||||
worlds: 'public/worlds/',
|
||||
avatars: 'public/User Avatars',
|
||||
groups: 'public/groups/',
|
||||
groupChats: 'public/group chats',
|
||||
};
|
||||
|
||||
// CSRF Protection //
|
||||
const doubleCsrf = require('csrf-csrf').doubleCsrf;
|
||||
@@ -286,6 +290,38 @@ app.post("/generate", jsonParser, function(request, response_generate = response
|
||||
response_generate.send({error: true});
|
||||
});
|
||||
});
|
||||
|
||||
//************** Text generation web UI
|
||||
app.post("/generate_textgenerationwebui", jsonParser, function(request, response_generate = response){
|
||||
if(!request.body) return response_generate.sendStatus(400);
|
||||
|
||||
console.log(request.body);
|
||||
var args = {
|
||||
data: request.body,
|
||||
headers: { "Content-Type": "application/json" }
|
||||
};
|
||||
client.post(api_server+"/run/textgen",args, function (data, response) {
|
||||
console.log("####", data);
|
||||
if(response.statusCode == 200){
|
||||
console.log(data);
|
||||
response_generate.send(data);
|
||||
}
|
||||
if(response.statusCode == 422){
|
||||
console.log('Validation error');
|
||||
response_generate.send({error: true});
|
||||
}
|
||||
if(response.statusCode == 501 || response.statusCode == 503 || response.statusCode == 507){
|
||||
console.log(data);
|
||||
response_generate.send({error: true});
|
||||
}
|
||||
}).on('error', function (err) {
|
||||
console.log(err);
|
||||
//console.log('something went wrong on the request', err.request.options);
|
||||
response_generate.send({error: true});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
app.post("/savechat", jsonParser, function(request, response){
|
||||
//console.log(humanizedISO8601DateTime()+':/savechat/ entered');
|
||||
//console.log(request.data);
|
||||
@@ -372,19 +408,39 @@ app.post("/getchat", jsonParser, function(request, response){
|
||||
app.post("/getstatus", jsonParser, function(request, response_getstatus = response){
|
||||
if(!request.body) return response_getstatus.sendStatus(400);
|
||||
api_server = request.body.api_server;
|
||||
main_api = request.body.main_api;
|
||||
if(api_server.indexOf('localhost') != -1){
|
||||
api_server = api_server.replace('localhost','127.0.0.1');
|
||||
}
|
||||
var args = {
|
||||
headers: { "Content-Type": "application/json" }
|
||||
};
|
||||
client.get(api_server+"/v1/model",args, function (data, response) {
|
||||
var url = api_server+"/v1/model";
|
||||
if (main_api == "textgenerationwebui") {
|
||||
url = api_server;
|
||||
args = {}
|
||||
}
|
||||
client.get(url,args, function (data, response) {
|
||||
if(response.statusCode == 200){
|
||||
if(data.result != "ReadOnly"){
|
||||
|
||||
//response_getstatus.send(data.result);
|
||||
}else{
|
||||
data.result = "no_connection";
|
||||
if (main_api == "textgenerationwebui") {
|
||||
// console.log(body);
|
||||
try {
|
||||
var body = data.toString();
|
||||
var response = body.match(/gradio_config[ =]*(\{.*\});/)[1];
|
||||
if (!response)
|
||||
throw "no_connection";
|
||||
data = {result: JSON.parse(response).components.filter( (x) => x.props.label == "Model" )[0].props.value};
|
||||
if (!data)
|
||||
throw "no_connection";
|
||||
} catch {
|
||||
data = {result: "no_connection"};
|
||||
}
|
||||
} else {
|
||||
if(data.result != "ReadOnly"){
|
||||
//response_getstatus.send(data.result);
|
||||
}else{
|
||||
data.result = "no_connection";
|
||||
}
|
||||
}
|
||||
}else{
|
||||
data.result = "no_connection";
|
||||
@@ -395,8 +451,8 @@ app.post("/getstatus", jsonParser, function(request, response_getstatus = respon
|
||||
//response_getstatus.send(data);
|
||||
//data.results[0].text
|
||||
}).on('error', function (err) {
|
||||
//console.log('');
|
||||
//console.log('something went wrong on the request', err.request.options);
|
||||
//console.log(url);
|
||||
//console.log('something went wrong on the request', err.request.options);
|
||||
response_getstatus.send({result: "no_connection"});
|
||||
});
|
||||
});
|
||||
@@ -464,7 +520,7 @@ function checkServer(){
|
||||
|
||||
//***************** Main functions
|
||||
function charaFormatData(data){
|
||||
var char = {"name": data.ch_name, "description": data.description, "personality": data.personality, "first_mes": data.first_mes, "avatar": 'none', "chat": data.ch_name+' - '+humanizedISO8601DateTime(), "mes_example": data.mes_example, "scenario": data.scenario, "create_date": humanizedISO8601DateTime};
|
||||
var char = {"name": data.ch_name, "description": data.description, "personality": data.personality, "first_mes": data.first_mes, "avatar": 'none', "chat": data.ch_name+' - '+humanizedISO8601DateTime(), "mes_example": data.mes_example, "scenario": data.scenario, "create_date": humanizedISO8601DateTime(), "talkativeness": data.talkativeness};
|
||||
return char;
|
||||
}
|
||||
app.post("/createcharacter", urlencodedParser, function(request, response){
|
||||
@@ -827,7 +883,8 @@ app.post('/getsettings', jsonParser, (request, response) => { //Wintermute's cod
|
||||
koboldai_setting_names,
|
||||
world_names,
|
||||
novelai_settings,
|
||||
novelai_setting_names
|
||||
novelai_setting_names,
|
||||
enable_extensions: enableExtensions,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1105,12 +1162,12 @@ app.post("/importcharacter", urlencodedParser, async function(request, response)
|
||||
|
||||
if(jsonData.name !== undefined){
|
||||
png_name = getPngName(jsonData.name);
|
||||
let char = {"name": jsonData.name, "description": jsonData.description ?? '', "personality": jsonData.personality ?? '', "first_mes": jsonData.first_mes ?? '', "avatar": 'none', "chat": humanizedISO8601DateTime(), "mes_example": jsonData.mes_example ?? '', "scenario": jsonData.scenario ?? '', "create_date": humanizedISO8601DateTime};
|
||||
let char = {"name": jsonData.name, "description": jsonData.description ?? '', "personality": jsonData.personality ?? '', "first_mes": jsonData.first_mes ?? '', "avatar": 'none', "chat": humanizedISO8601DateTime(), "mes_example": jsonData.mes_example ?? '', "scenario": jsonData.scenario ?? '', "create_date": humanizedISO8601DateTime(), "talkativeness": jsonData.talkativeness ?? 0.5};
|
||||
char = JSON.stringify(char);
|
||||
charaWrite('./public/img/fluffy.png', char, png_name, response, {file_name: png_name});
|
||||
}else if(jsonData.char_name !== undefined){//json Pygmalion notepad
|
||||
png_name = getPngName(jsonData.char_name);
|
||||
let char = {"name": jsonData.char_name, "description": jsonData.char_persona ?? '', "personality": '', "first_mes": jsonData.char_greeting ?? '', "avatar": 'none', "chat": humanizedISO8601DateTime(), "mes_example": jsonData.example_dialogue ?? '', "scenario": jsonData.world_scenario ?? '', "create_date": humanizedISO8601DateTime};
|
||||
let char = {"name": jsonData.char_name, "description": jsonData.char_persona ?? '', "personality": '', "first_mes": jsonData.char_greeting ?? '', "avatar": 'none', "chat": humanizedISO8601DateTime(), "mes_example": jsonData.example_dialogue ?? '', "scenario": jsonData.world_scenario ?? '', "create_date": humanizedISO8601DateTime(), "talkativeness": jsonData.talkativeness ?? 0.5};
|
||||
char = JSON.stringify(char);
|
||||
charaWrite('./public/img/fluffy.png', char, png_name, response, {file_name: png_name});
|
||||
}else{
|
||||
@@ -1126,7 +1183,7 @@ app.post("/importcharacter", urlencodedParser, async function(request, response)
|
||||
png_name = getPngName(jsonData.name);
|
||||
|
||||
if(jsonData.name !== undefined){
|
||||
let char = {"name": jsonData.name, "description": jsonData.description ?? '', "personality": jsonData.personality ?? '', "first_mes": jsonData.first_mes ?? '', "avatar": 'none', "chat": humanizedISO8601DateTime(), "mes_example": jsonData.mes_example ?? '', "scenario": jsonData.scenario ?? '', "create_date": humanizedISO8601DateTime};
|
||||
let char = {"name": jsonData.name, "description": jsonData.description ?? '', "personality": jsonData.personality ?? '', "first_mes": jsonData.first_mes ?? '', "avatar": 'none', "chat": humanizedISO8601DateTime(), "mes_example": jsonData.mes_example ?? '', "scenario": jsonData.scenario ?? '', "create_date": humanizedISO8601DateTime(), "talkativeness": jsonData.talkativeness ?? 0.5};
|
||||
char = JSON.stringify(char);
|
||||
await charaWrite('./uploads/'+filedata.filename, char, png_name, response, {file_name: png_name});
|
||||
/*
|
||||
@@ -1330,6 +1387,112 @@ app.post('/uploaduseravatar', urlencodedParser, async (request, response) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/getgroups', jsonParser, (_, response) => {
|
||||
const groups = [];
|
||||
|
||||
if (!fs.existsSync(directories.groups)) {
|
||||
fs.mkdirSync(directories.groups);
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(directories.groups);
|
||||
files.forEach(function(file) {
|
||||
const fileContents = fs.readFileSync(path.join(directories.groups, file), 'utf8');
|
||||
const group = JSON.parse(fileContents);
|
||||
groups.push(group);
|
||||
});
|
||||
|
||||
return response.send(groups);
|
||||
});
|
||||
|
||||
app.post('/creategroup', jsonParser, (request, response) => {
|
||||
if (!request.body) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const id = Date.now();
|
||||
const chatMetadata = { id: id, name: request.body.name ?? 'New Group', members: request.body.members ?? [], avatar_url: request.body.avatar_url };
|
||||
const pathToFile = path.join(directories.groups, `${id}.json`);
|
||||
const fileData = JSON.stringify(chatMetadata);
|
||||
|
||||
if (!fs.existsSync(directories.groups)) {
|
||||
fs.mkdirSync(directories.groups);
|
||||
}
|
||||
|
||||
fs.writeFileSync(pathToFile, fileData);
|
||||
return response.send(chatMetadata);
|
||||
});
|
||||
|
||||
app.post('/editgroup', jsonParser, (request, response) => {
|
||||
if (!request.body || !request.body.id) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const id = request.body.id;
|
||||
const pathToFile = path.join(directories.groups, `${id}.json`);
|
||||
const fileData = JSON.stringify(request.body);
|
||||
|
||||
fs.writeFileSync(pathToFile, fileData);
|
||||
return response.send({ok: true});
|
||||
});
|
||||
|
||||
app.post('/getgroupchat', jsonParser, (request, response) => {
|
||||
if (!request.body || !request.body.id) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const id = request.body.id;
|
||||
const pathToFile = path.join(directories.groupChats, `${id}.jsonl`);
|
||||
|
||||
if (fs.existsSync(pathToFile)) {
|
||||
const data = fs.readFileSync(pathToFile, 'utf8');
|
||||
const lines = data.split('\n');
|
||||
|
||||
// Iterate through the array of strings and parse each line as JSON
|
||||
const jsonData = lines.map(JSON.parse);
|
||||
return response.send(jsonData);
|
||||
} else {
|
||||
return response.send([]);
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/savegroupchat', jsonParser, (request, response) => {
|
||||
if (!request.body || !request.body.id) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const id = request.body.id;
|
||||
const pathToFile = path.join(directories.groupChats, `${id}.jsonl`);
|
||||
|
||||
if (!fs.existsSync(directories.groupChats)) {
|
||||
fs.mkdirSync(directories.groupChats);
|
||||
}
|
||||
|
||||
let chat_data = request.body.chat;
|
||||
let jsonlData = chat_data.map(JSON.stringify).join('\n');
|
||||
fs.writeFileSync(pathToFile, jsonlData, 'utf8');
|
||||
return response.send({ok: true});
|
||||
});
|
||||
|
||||
app.post('/deletegroup', jsonParser, async (request, response) => {
|
||||
if (!request.body || !request.body.id) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const id = request.body.id;
|
||||
const pathToGroup = path.join(directories.groups, `${id}.json`);
|
||||
const pathToChat = path.join(directories.groupChats, `${id}.jsonl`);
|
||||
|
||||
if (fs.existsSync(pathToGroup)) {
|
||||
fs.rmSync(pathToGroup);
|
||||
}
|
||||
|
||||
if (fs.existsSync(pathToChat)) {
|
||||
fs.rmSync(pathToChat);
|
||||
}
|
||||
|
||||
return response.send({ok: true});
|
||||
});
|
||||
|
||||
// ** REST CLIENT ASYNC WRAPPERS **
|
||||
function deleteAsync(url, args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
Reference in New Issue
Block a user