sillytavern 1.10.1 → 1.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/readme-zh_cn.md +0 -2
- package/.github/readme.md +0 -3
- package/package.json +1 -4
- package/public/i18n.json +0 -6
- package/public/index.html +1 -2
- package/public/script.js +25 -12
- package/public/scripts/group-chats.js +3 -7
- package/public/scripts/openai.js +6 -2
- package/public/style.css +2 -1
- package/server.js +20 -100
- package/src/character-card-parser.js +1 -45
- package/Launcher.bat +0 -641
- package/tools/charaverter/main.mjs +0 -117
- package/tools/charaverter/package.json +0 -10
package/.github/readme-zh_cn.md
CHANGED
package/.github/readme.md
CHANGED
|
@@ -41,8 +41,6 @@ Since Tavern is only a user interface, it has tiny hardware requirements, it wil
|
|
|
41
41
|
|
|
42
42
|
<https://rentry.org/STAI-Termux>
|
|
43
43
|
|
|
44
|
-
**.webp character cards import/export is not supported in Termux. Use either JSON or PNG formats instead.**
|
|
45
|
-
|
|
46
44
|
## Questions or suggestions?
|
|
47
45
|
|
|
48
46
|
### We now have a community Discord server
|
|
@@ -71,7 +69,6 @@ Get in touch with the developers directly:
|
|
|
71
69
|
* [Oobabooga's TextGen WebUI](https://github.com/oobabooga/text-generation-webui) API connection
|
|
72
70
|
* [AI Horde](https://horde.koboldai.net/) connection
|
|
73
71
|
* Prompt generation formatting tweaking
|
|
74
|
-
* webp character card interoperability (PNG is still an internal format)
|
|
75
72
|
|
|
76
73
|
## Extensions
|
|
77
74
|
|
package/package.json
CHANGED
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"cors": "^2.8.5",
|
|
10
10
|
"csrf-csrf": "^2.2.3",
|
|
11
11
|
"device-detector-js": "^3.0.3",
|
|
12
|
-
"exifreader": "^4.12.0",
|
|
13
12
|
"express": "^4.18.2",
|
|
14
13
|
"google-translate-api-browser": "^3.0.1",
|
|
15
14
|
"gpt3-tokenizer": "^1.1.5",
|
|
@@ -23,7 +22,6 @@
|
|
|
23
22
|
"multer": "^1.4.5-lts.1",
|
|
24
23
|
"node-fetch": "^2.6.11",
|
|
25
24
|
"open": "^8.4.2",
|
|
26
|
-
"piexifjs": "^1.0.6",
|
|
27
25
|
"png-chunk-text": "^1.0.0",
|
|
28
26
|
"png-chunks-encode": "^1.0.0",
|
|
29
27
|
"png-chunks-extract": "^1.0.0",
|
|
@@ -31,7 +29,6 @@
|
|
|
31
29
|
"sanitize-filename": "^1.6.3",
|
|
32
30
|
"simple-git": "^3.19.1",
|
|
33
31
|
"uniqolor": "^1.1.0",
|
|
34
|
-
"webp-converter": "2.3.2",
|
|
35
32
|
"write-file-atomic": "^5.0.1",
|
|
36
33
|
"ws": "^8.13.0",
|
|
37
34
|
"yargs": "^17.7.1",
|
|
@@ -49,7 +46,7 @@
|
|
|
49
46
|
"type": "git",
|
|
50
47
|
"url": "https://github.com/SillyTavern/SillyTavern.git"
|
|
51
48
|
},
|
|
52
|
-
"version": "1.10.
|
|
49
|
+
"version": "1.10.3",
|
|
53
50
|
"scripts": {
|
|
54
51
|
"start": "node server.js",
|
|
55
52
|
"start-multi": "node server.js --disableCsrf",
|
package/public/i18n.json
CHANGED
|
@@ -284,7 +284,6 @@
|
|
|
284
284
|
"Regenerate": "重新生成",
|
|
285
285
|
"PNG": "PNG",
|
|
286
286
|
"JSON": "JSON",
|
|
287
|
-
"WEBP": "WEBP",
|
|
288
287
|
"presets": "预设",
|
|
289
288
|
"Message Sound": "AI 消息提示音",
|
|
290
289
|
"Author's Note": "作者注释",
|
|
@@ -836,7 +835,6 @@
|
|
|
836
835
|
"Regenerate": "再生成",
|
|
837
836
|
"PNG": "PNG",
|
|
838
837
|
"JSON": "JSON",
|
|
839
|
-
"WEBP": "WEBP",
|
|
840
838
|
"presets": "プリセット",
|
|
841
839
|
"Message Sound": "メッセージ音",
|
|
842
840
|
"Author's Note": "作者の注記",
|
|
@@ -1392,7 +1390,6 @@
|
|
|
1392
1390
|
"Regenerate": "재생성",
|
|
1393
1391
|
"PNG": "PNG",
|
|
1394
1392
|
"JSON": "JSON",
|
|
1395
|
-
"WEBP": "WEBP",
|
|
1396
1393
|
"presets": "기본설정",
|
|
1397
1394
|
"Message Sound": "메시지 효과음",
|
|
1398
1395
|
"Author's Note": "글쓴이 쪽지",
|
|
@@ -2016,7 +2013,6 @@
|
|
|
2016
2013
|
"Regenerate": "Повторная генерация",
|
|
2017
2014
|
"PNG": "PNG",
|
|
2018
2015
|
"JSON": "JSON",
|
|
2019
|
-
"WEBP": "WEBP",
|
|
2020
2016
|
"presets": "Предустановки",
|
|
2021
2017
|
"Message Sound": "Звук сообщения",
|
|
2022
2018
|
"Author's Note": "Авторские заметки",
|
|
@@ -2580,7 +2576,6 @@
|
|
|
2580
2576
|
"Regenerate": "Rigenera",
|
|
2581
2577
|
"PNG": "PNG",
|
|
2582
2578
|
"JSON": "JSON",
|
|
2583
|
-
"WEBP": "WEBP",
|
|
2584
2579
|
"presets": "preset",
|
|
2585
2580
|
"Message Sound": "Suono del messaggio",
|
|
2586
2581
|
"Author's Note": "Note d'autore",
|
|
@@ -3259,7 +3254,6 @@
|
|
|
3259
3254
|
"Regenerate": "Regenereren",
|
|
3260
3255
|
"PNG": "PNG",
|
|
3261
3256
|
"JSON": "JSON",
|
|
3262
|
-
"WEBP": "WEBP",
|
|
3263
3257
|
"presets": "sjablonen",
|
|
3264
3258
|
"Message Sound": "Berichtgeluid",
|
|
3265
3259
|
"Author's Note": "Notitie van auteur",
|
package/public/index.html
CHANGED
|
@@ -3482,7 +3482,7 @@
|
|
|
3482
3482
|
|
|
3483
3483
|
<div id="rm_character_import" class="right_menu" style="display: none;">
|
|
3484
3484
|
<form id="form_import" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
|
3485
|
-
<input multiple type="file" id="character_import_file" accept=".json, image/png
|
|
3485
|
+
<input multiple type="file" id="character_import_file" accept=".json, image/png" name="avatar">
|
|
3486
3486
|
<input id="character_import_file_type" name="file_type" class="text_pole" maxlength="999" size="2" value="" autocomplete="off">
|
|
3487
3487
|
</form>
|
|
3488
3488
|
</div>
|
|
@@ -4445,7 +4445,6 @@
|
|
|
4445
4445
|
<div id="export_format_popup" class="list-group">
|
|
4446
4446
|
<div class="export_format list-group-item" data-format="png">PNG</div>
|
|
4447
4447
|
<div class="export_format list-group-item" data-format="json">JSON</div>
|
|
4448
|
-
<div class="export_format list-group-item" data-format="webp">WEBP</div>
|
|
4449
4448
|
</div>
|
|
4450
4449
|
|
|
4451
4450
|
<div id="zoomed_avatar_template" class="template_element">
|
package/public/script.js
CHANGED
|
@@ -5410,17 +5410,18 @@ function select_rm_info(type, charId, previousCharId = null) {
|
|
|
5410
5410
|
$('#rm_print_characters_pagination').pagination('go', page);
|
|
5411
5411
|
|
|
5412
5412
|
waitUntilCondition(() => document.querySelector(selector) !== null).then(() => {
|
|
5413
|
-
const
|
|
5413
|
+
const parent = $('#rm_print_characters_block');
|
|
5414
|
+
const element = $(selector).parent();
|
|
5414
5415
|
|
|
5415
|
-
if (
|
|
5416
|
+
if (element.length === 0) {
|
|
5416
5417
|
console.log(`Could not find element for character ${charId}`);
|
|
5417
5418
|
return;
|
|
5418
5419
|
}
|
|
5419
5420
|
|
|
5420
|
-
element.
|
|
5421
|
-
|
|
5421
|
+
parent.scrollTop(element.position().top + parent.scrollTop());
|
|
5422
|
+
element.addClass('flash animated');
|
|
5422
5423
|
setTimeout(function () {
|
|
5423
|
-
|
|
5424
|
+
element.removeClass('flash animated');
|
|
5424
5425
|
}, 5000);
|
|
5425
5426
|
});
|
|
5426
5427
|
} catch (e) {
|
|
@@ -5429,16 +5430,29 @@ function select_rm_info(type, charId, previousCharId = null) {
|
|
|
5429
5430
|
}
|
|
5430
5431
|
|
|
5431
5432
|
if (type === 'group_create') {
|
|
5432
|
-
//
|
|
5433
|
-
const
|
|
5434
|
-
|
|
5433
|
+
// Find the page at which the character is located
|
|
5434
|
+
const charData = getEntitiesList({ doFilter: true });
|
|
5435
|
+
const charIndex = charData.findIndex((x) => String(x?.item?.id) === String(charId));
|
|
5436
|
+
|
|
5437
|
+
if (charIndex === -1) {
|
|
5438
|
+
console.log(`Could not find group ${charId} in the list`);
|
|
5439
|
+
return;
|
|
5440
|
+
}
|
|
5441
|
+
|
|
5442
|
+
const perPage = Number(localStorage.getItem('Characters_PerPage'));
|
|
5443
|
+
const page = Math.floor(charIndex / perPage) + 1;
|
|
5444
|
+
$('#rm_print_characters_pagination').pagination('go', page);
|
|
5445
|
+
const parent = $('#rm_print_characters_block');
|
|
5446
|
+
const selector = `#rm_print_characters_block [grid="${charId}"]`;
|
|
5435
5447
|
try {
|
|
5436
|
-
|
|
5448
|
+
waitUntilCondition(() => document.querySelector(selector) !== null).then(() => {
|
|
5449
|
+
const element = $(selector);
|
|
5450
|
+
parent.scrollTop(element.position().top + parent.scrollTop());
|
|
5437
5451
|
$(element).addClass('flash animated');
|
|
5438
5452
|
setTimeout(function () {
|
|
5439
5453
|
$(element).removeClass('flash animated');
|
|
5440
5454
|
}, 5000);
|
|
5441
|
-
}
|
|
5455
|
+
});
|
|
5442
5456
|
} catch (e) {
|
|
5443
5457
|
console.error(e);
|
|
5444
5458
|
}
|
|
@@ -6732,7 +6746,6 @@ export function processDroppedFiles(files) {
|
|
|
6732
6746
|
const allowedMimeTypes = [
|
|
6733
6747
|
'application/json',
|
|
6734
6748
|
'image/png',
|
|
6735
|
-
'image/webp',
|
|
6736
6749
|
];
|
|
6737
6750
|
|
|
6738
6751
|
for (const file of files) {
|
|
@@ -6748,7 +6761,7 @@ function importCharacter(file) {
|
|
|
6748
6761
|
const ext = file.name.match(/\.(\w+)$/);
|
|
6749
6762
|
if (
|
|
6750
6763
|
!ext ||
|
|
6751
|
-
(ext[1].toLowerCase() != "json" && ext[1].toLowerCase() != "png"
|
|
6764
|
+
(ext[1].toLowerCase() != "json" && ext[1].toLowerCase() != "png")
|
|
6752
6765
|
) {
|
|
6753
6766
|
return;
|
|
6754
6767
|
}
|
|
@@ -582,10 +582,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
|
|
|
582
582
|
typingIndicator
|
|
583
583
|
.find(".typing_indicator_name")
|
|
584
584
|
.text(characters[chId].name);
|
|
585
|
-
|
|
586
|
-
typingIndicator.show(200, function () {
|
|
587
|
-
typingIndicator.get(0).scrollIntoView({ behavior: "smooth" });
|
|
588
|
-
});
|
|
585
|
+
typingIndicator.show();
|
|
589
586
|
}
|
|
590
587
|
|
|
591
588
|
// TODO: This is awful. Refactor this
|
|
@@ -681,9 +678,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
|
|
|
681
678
|
}
|
|
682
679
|
}
|
|
683
680
|
} finally {
|
|
684
|
-
|
|
685
|
-
typingIndicator.hide(200);
|
|
686
|
-
$("#chat").append(typingIndicator);
|
|
681
|
+
typingIndicator.hide();
|
|
687
682
|
|
|
688
683
|
is_group_generating = false;
|
|
689
684
|
$("#send_textarea").attr("disabled", false);
|
|
@@ -1109,6 +1104,7 @@ function select_group_chats(groupId, skipAnimation) {
|
|
|
1109
1104
|
$("#rm_group_restore_avatar").toggle(!!group && isValidImageUrl(group.avatar_url));
|
|
1110
1105
|
$("#rm_group_filter").val("").trigger("input");
|
|
1111
1106
|
$(`input[name="rm_group_activation_strategy"][value="${replyStrategy}"]`).prop('checked', true);
|
|
1107
|
+
$("#rm_group_chat_name").val(groupName);
|
|
1112
1108
|
|
|
1113
1109
|
if (!skipAnimation) {
|
|
1114
1110
|
selectRightMenuWithAnimation('rm_group_chats_block');
|
package/public/scripts/openai.js
CHANGED
|
@@ -576,6 +576,7 @@ function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, ty
|
|
|
576
576
|
chatCompletion.add(collection, index);
|
|
577
577
|
};
|
|
578
578
|
|
|
579
|
+
chatCompletion.reserveBudget(3); // every reply is primed with <|start|>assistant<|message|>
|
|
579
580
|
// Character and world information
|
|
580
581
|
addToChatCompletion('worldInfoBefore');
|
|
581
582
|
addToChatCompletion('main');
|
|
@@ -1761,9 +1762,12 @@ class ChatCompletion {
|
|
|
1761
1762
|
/**
|
|
1762
1763
|
* Reserves the tokens required by the given message from the token budget.
|
|
1763
1764
|
*
|
|
1764
|
-
* @param {Message|MessageCollection} message - The message whose tokens to reserve.
|
|
1765
|
+
* @param {Message|MessageCollection|number} message - The message whose tokens to reserve.
|
|
1765
1766
|
*/
|
|
1766
|
-
reserveBudget(message) {
|
|
1767
|
+
reserveBudget(message) {
|
|
1768
|
+
const tokens = typeof message === 'number' ? message : message.getTokens();
|
|
1769
|
+
this.decreaseTokenBudgetBy(tokens);
|
|
1770
|
+
};
|
|
1767
1771
|
|
|
1768
1772
|
/**
|
|
1769
1773
|
* Frees up the tokens used by the given message from the token budget.
|
package/public/style.css
CHANGED
|
@@ -2768,6 +2768,7 @@ body .ui-widget-content li:hover {
|
|
|
2768
2768
|
margin: 10px;
|
|
2769
2769
|
opacity: 0.85;
|
|
2770
2770
|
text-shadow: 0px 0px calc(var(--shadowWidth) * 1px) var(--SmartThemeShadowColor);
|
|
2771
|
+
order: 9999;
|
|
2771
2772
|
}
|
|
2772
2773
|
|
|
2773
2774
|
.typing_indicator:after {
|
|
@@ -3608,4 +3609,4 @@ a {
|
|
|
3608
3609
|
height: 100vh;
|
|
3609
3610
|
z-index: 9999;
|
|
3610
3611
|
}
|
|
3611
|
-
}
|
|
3612
|
+
}
|
package/server.js
CHANGED
|
@@ -32,6 +32,8 @@ const multer = require("multer");
|
|
|
32
32
|
const responseTime = require('response-time');
|
|
33
33
|
|
|
34
34
|
// net related library imports
|
|
35
|
+
const net = require("net");
|
|
36
|
+
const dns = require('dns');
|
|
35
37
|
const DeviceDetector = require("device-detector-js");
|
|
36
38
|
const fetch = require('node-fetch').default;
|
|
37
39
|
const ipaddr = require('ipaddr.js');
|
|
@@ -40,13 +42,11 @@ const json5 = require('json5');
|
|
|
40
42
|
const WebSocket = require('ws');
|
|
41
43
|
|
|
42
44
|
// image processing related library imports
|
|
43
|
-
const exif = require('piexifjs');
|
|
44
45
|
const encode = require('png-chunks-encode');
|
|
45
46
|
const extract = require('png-chunks-extract');
|
|
46
47
|
const jimp = require('jimp');
|
|
47
48
|
const mime = require('mime-types');
|
|
48
49
|
const PNGtext = require('png-chunk-text');
|
|
49
|
-
const webp = require('webp-converter');
|
|
50
50
|
const yauzl = require('yauzl');
|
|
51
51
|
|
|
52
52
|
// tokenizing related library imports
|
|
@@ -89,9 +89,16 @@ function createDefaultFiles() {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
|
|
92
|
+
// Work around a node v20.0.0, v20.1.0, and v20.2.0 bug. The issue was fixed in v20.3.0.
|
|
93
|
+
// https://github.com/nodejs/node/issues/47822#issuecomment-1564708870
|
|
94
|
+
// Safe to remove once support for Node v20 is dropped.
|
|
95
|
+
if (process.versions && process.versions.node && process.versions.node.match(/20\.[0-2]\.0/)) {
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
if (net.setDefaultAutoSelectFamily) net.setDefaultAutoSelectFamily(false);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Set default DNS resolution order to IPv4 first
|
|
101
|
+
dns.setDefaultResultOrder('ipv4first');
|
|
95
102
|
|
|
96
103
|
const cliArguments = yargs(hideBin(process.argv))
|
|
97
104
|
.option('disableCsrf', {
|
|
@@ -1128,7 +1135,7 @@ app.post("/renamecharacter", jsonParser, async function (request, response) {
|
|
|
1128
1135
|
try {
|
|
1129
1136
|
// Read old file, replace name int it
|
|
1130
1137
|
const rawOldData = await charaRead(oldAvatarPath);
|
|
1131
|
-
if (rawOldData ===
|
|
1138
|
+
if (rawOldData === undefined) throw new Error("Failed to read character file");
|
|
1132
1139
|
|
|
1133
1140
|
const oldData = getCharaCardV2(json5.parse(rawOldData));
|
|
1134
1141
|
_.set(oldData, 'data.name', newName);
|
|
@@ -1375,7 +1382,7 @@ const calculateDataSize = (data) => {
|
|
|
1375
1382
|
const processCharacter = async (item, i) => {
|
|
1376
1383
|
try {
|
|
1377
1384
|
const img_data = await charaRead(charactersPath + item);
|
|
1378
|
-
if (img_data ===
|
|
1385
|
+
if (img_data === undefined) throw new Error("Failed to read character file");
|
|
1379
1386
|
|
|
1380
1387
|
let jsonObject = getCharaCardV2(json5.parse(img_data));
|
|
1381
1388
|
jsonObject.avatar = item;
|
|
@@ -2212,26 +2219,13 @@ app.post("/importcharacter", urlencodedParser, async function (request, response
|
|
|
2212
2219
|
} else {
|
|
2213
2220
|
try {
|
|
2214
2221
|
var img_data = await charaRead(uploadPath, format);
|
|
2215
|
-
if (img_data ===
|
|
2222
|
+
if (img_data === undefined) throw new Error('Failed to read character data');
|
|
2216
2223
|
|
|
2217
2224
|
let jsonData = json5.parse(img_data);
|
|
2218
2225
|
|
|
2219
2226
|
jsonData.name = sanitize(jsonData.data?.name || jsonData.name);
|
|
2220
2227
|
png_name = getPngName(jsonData.name);
|
|
2221
2228
|
|
|
2222
|
-
if (format == 'webp') {
|
|
2223
|
-
try {
|
|
2224
|
-
let convertedPath = path.join(UPLOADS_PATH, path.basename(uploadPath, ".webp") + ".png")
|
|
2225
|
-
await webp.dwebp(uploadPath, convertedPath, "-o");
|
|
2226
|
-
fs.unlinkSync(uploadPath);
|
|
2227
|
-
uploadPath = convertedPath;
|
|
2228
|
-
}
|
|
2229
|
-
catch {
|
|
2230
|
-
console.error('WEBP image conversion failed. Using the default character image.');
|
|
2231
|
-
uploadPath = defaultAvatarPath;
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
2234
|
-
|
|
2235
2229
|
if (jsonData.spec !== undefined) {
|
|
2236
2230
|
console.log('Found a v2 character file.');
|
|
2237
2231
|
importRisuSprites(jsonData);
|
|
@@ -2411,7 +2405,7 @@ app.post("/exportcharacter", jsonParser, async function (request, response) {
|
|
|
2411
2405
|
case 'json': {
|
|
2412
2406
|
try {
|
|
2413
2407
|
let json = await charaRead(filename);
|
|
2414
|
-
if (json ===
|
|
2408
|
+
if (json === undefined) return response.sendStatus(400);
|
|
2415
2409
|
let jsonObject = getCharaCardV2(json5.parse(json));
|
|
2416
2410
|
return response.type('json').send(jsonObject)
|
|
2417
2411
|
}
|
|
@@ -2419,39 +2413,6 @@ app.post("/exportcharacter", jsonParser, async function (request, response) {
|
|
|
2419
2413
|
return response.sendStatus(400);
|
|
2420
2414
|
}
|
|
2421
2415
|
}
|
|
2422
|
-
case 'webp': {
|
|
2423
|
-
try {
|
|
2424
|
-
let json = await charaRead(filename);
|
|
2425
|
-
if (json === false || json === undefined) return response.sendStatus(400);
|
|
2426
|
-
let stringByteArray = utf8Encode.encode(json).toString();
|
|
2427
|
-
let inputWebpPath = path.join(UPLOADS_PATH, `${Date.now()}_input.webp`);
|
|
2428
|
-
let outputWebpPath = path.join(UPLOADS_PATH, `${Date.now()}_output.webp`);
|
|
2429
|
-
let metadataPath = path.join(UPLOADS_PATH, `${Date.now()}_metadata.exif`);
|
|
2430
|
-
let metadata =
|
|
2431
|
-
{
|
|
2432
|
-
"Exif": {
|
|
2433
|
-
[exif.ExifIFD.UserComment]: stringByteArray,
|
|
2434
|
-
},
|
|
2435
|
-
};
|
|
2436
|
-
const exifString = exif.dump(metadata);
|
|
2437
|
-
writeFileAtomicSync(metadataPath, exifString, 'binary');
|
|
2438
|
-
|
|
2439
|
-
await webp.cwebp(filename, inputWebpPath, '-q 95');
|
|
2440
|
-
await webp.webpmux_add(inputWebpPath, outputWebpPath, metadataPath, 'exif');
|
|
2441
|
-
|
|
2442
|
-
response.sendFile(outputWebpPath, { root: process.cwd() }, () => {
|
|
2443
|
-
fs.rmSync(inputWebpPath);
|
|
2444
|
-
fs.rmSync(metadataPath);
|
|
2445
|
-
fs.rmSync(outputWebpPath);
|
|
2446
|
-
});
|
|
2447
|
-
|
|
2448
|
-
return;
|
|
2449
|
-
}
|
|
2450
|
-
catch (err) {
|
|
2451
|
-
console.log(err);
|
|
2452
|
-
return response.sendStatus(400);
|
|
2453
|
-
}
|
|
2454
|
-
}
|
|
2455
2416
|
}
|
|
2456
2417
|
|
|
2457
2418
|
return response.sendStatus(400);
|
|
@@ -4005,8 +3966,10 @@ app.post("/tokenize_via_api", jsonParser, async function (request, response) {
|
|
|
4005
3966
|
headers: { "Content-Type": "application/json" }
|
|
4006
3967
|
};
|
|
4007
3968
|
|
|
4008
|
-
if (main_api == 'textgenerationwebui'
|
|
4009
|
-
|
|
3969
|
+
if (main_api == 'textgenerationwebui') {
|
|
3970
|
+
if (request.body.use_mancer) {
|
|
3971
|
+
args.headers = Object.assign(args.headers, get_mancer_headers());
|
|
3972
|
+
}
|
|
4010
3973
|
const data = await postAsync(api_server + "/v1/token-count", args);
|
|
4011
3974
|
return response.send({ count: data['results'][0]['tokens'] });
|
|
4012
3975
|
}
|
|
@@ -4078,8 +4041,6 @@ const setupTasks = async function () {
|
|
|
4078
4041
|
contentManager.checkForNewContent();
|
|
4079
4042
|
cleanUploads();
|
|
4080
4043
|
|
|
4081
|
-
await convertWebp();
|
|
4082
|
-
|
|
4083
4044
|
[spp_llama, spp_nerd, spp_nerd_v2, claude_tokenizer] = await Promise.all([
|
|
4084
4045
|
loadSentencepieceTokenizer('src/sentencepiece/tokenizer.model'),
|
|
4085
4046
|
loadSentencepieceTokenizer('src/sentencepiece/nerdstash.model'),
|
|
@@ -4139,47 +4100,6 @@ if (true === cliArguments.ssl) {
|
|
|
4139
4100
|
);
|
|
4140
4101
|
}
|
|
4141
4102
|
|
|
4142
|
-
async function convertWebp() {
|
|
4143
|
-
const files = fs.readdirSync(directories.characters).filter(e => e.endsWith(".webp"));
|
|
4144
|
-
|
|
4145
|
-
if (!files.length) {
|
|
4146
|
-
return;
|
|
4147
|
-
}
|
|
4148
|
-
|
|
4149
|
-
console.log(`${files.length} WEBP files will be automatically converted.`);
|
|
4150
|
-
|
|
4151
|
-
for (const file of files) {
|
|
4152
|
-
try {
|
|
4153
|
-
const source = path.join(directories.characters, file);
|
|
4154
|
-
const dest = path.join(directories.characters, path.basename(file, ".webp") + ".png");
|
|
4155
|
-
|
|
4156
|
-
if (fs.existsSync(dest)) {
|
|
4157
|
-
console.log(`${dest} already exists. Delete ${source} manually`);
|
|
4158
|
-
continue;
|
|
4159
|
-
}
|
|
4160
|
-
|
|
4161
|
-
console.log(`Read... ${source}`);
|
|
4162
|
-
const data = await charaRead(source);
|
|
4163
|
-
|
|
4164
|
-
console.log(`Convert... ${source} -> ${dest}`);
|
|
4165
|
-
await webp.dwebp(source, dest, "-o");
|
|
4166
|
-
|
|
4167
|
-
console.log(`Write... ${dest}`);
|
|
4168
|
-
const success = await charaWrite(dest, data, path.parse(dest).name);
|
|
4169
|
-
|
|
4170
|
-
if (!success) {
|
|
4171
|
-
console.log(`Failure on ${source} -> ${dest}`);
|
|
4172
|
-
continue;
|
|
4173
|
-
}
|
|
4174
|
-
|
|
4175
|
-
console.log(`Remove... ${source}`);
|
|
4176
|
-
fs.rmSync(source);
|
|
4177
|
-
} catch (err) {
|
|
4178
|
-
console.log(err);
|
|
4179
|
-
}
|
|
4180
|
-
}
|
|
4181
|
-
}
|
|
4182
|
-
|
|
4183
4103
|
function backupSettings() {
|
|
4184
4104
|
const MAX_BACKUPS = 25;
|
|
4185
4105
|
|
|
@@ -1,56 +1,12 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
-
const json5 = require('json5');
|
|
3
|
-
const ExifReader = require('exifreader');
|
|
4
2
|
|
|
5
3
|
const extract = require('png-chunks-extract');
|
|
6
4
|
const PNGtext = require('png-chunk-text');
|
|
7
5
|
|
|
8
|
-
const utf8Decode = new TextDecoder('utf-8', { ignoreBOM: true });
|
|
9
|
-
|
|
10
6
|
const parse = async (cardUrl, format) => {
|
|
11
|
-
let fileFormat;
|
|
12
|
-
if (format === undefined) {
|
|
13
|
-
if (cardUrl.indexOf('.webp') !== -1)
|
|
14
|
-
fileFormat = 'webp';
|
|
15
|
-
else
|
|
16
|
-
fileFormat = 'png';
|
|
17
|
-
}
|
|
18
|
-
else
|
|
19
|
-
fileFormat = format;
|
|
7
|
+
let fileFormat = format === undefined ? 'png' : format;
|
|
20
8
|
|
|
21
9
|
switch (fileFormat) {
|
|
22
|
-
case 'webp':
|
|
23
|
-
try {
|
|
24
|
-
const exif_data = await ExifReader.load(fs.readFileSync(cardUrl));
|
|
25
|
-
let char_data;
|
|
26
|
-
|
|
27
|
-
if (exif_data['UserComment']['description']) {
|
|
28
|
-
let description = exif_data['UserComment']['description'];
|
|
29
|
-
if (description === 'Undefined' && exif_data['UserComment'].value && exif_data['UserComment'].value.length === 1) {
|
|
30
|
-
description = exif_data['UserComment'].value[0];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
json5.parse(description);
|
|
35
|
-
char_data = description;
|
|
36
|
-
} catch {
|
|
37
|
-
const byteArr = description.split(",").map(Number);
|
|
38
|
-
const uint8Array = new Uint8Array(byteArr);
|
|
39
|
-
const char_data_string = utf8Decode.decode(uint8Array);
|
|
40
|
-
char_data = char_data_string;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
console.log('No description found in EXIF data.');
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return char_data;
|
|
49
|
-
}
|
|
50
|
-
catch (err) {
|
|
51
|
-
console.log(err);
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
10
|
case 'png':
|
|
55
11
|
const buffer = fs.readFileSync(cardUrl);
|
|
56
12
|
const chunks = extract(buffer);
|
package/Launcher.bat
DELETED
|
@@ -1,641 +0,0 @@
|
|
|
1
|
-
@echo off
|
|
2
|
-
REM --------------------------------------------
|
|
3
|
-
REM This script was created by: Deffcolony
|
|
4
|
-
REM --------------------------------------------
|
|
5
|
-
title SillyTavern Launcher
|
|
6
|
-
setlocal
|
|
7
|
-
|
|
8
|
-
REM ANSI Escape Code for Colors
|
|
9
|
-
set "reset=[0m"
|
|
10
|
-
|
|
11
|
-
REM Strong Foreground Colors
|
|
12
|
-
set "white_fg_strong=[90m"
|
|
13
|
-
set "red_fg_strong=[91m"
|
|
14
|
-
set "green_fg_strong=[92m"
|
|
15
|
-
set "yellow_fg_strong=[93m"
|
|
16
|
-
set "blue_fg_strong=[94m"
|
|
17
|
-
set "magenta_fg_strong=[95m"
|
|
18
|
-
set "cyan_fg_strong=[96m"
|
|
19
|
-
|
|
20
|
-
REM Normal Background Colors
|
|
21
|
-
set "red_bg=[41m"
|
|
22
|
-
set "blue_bg=[44m"
|
|
23
|
-
|
|
24
|
-
REM Environment Variables (TOOLBOX 7-Zip)
|
|
25
|
-
set "zip7version=7z2301-x64"
|
|
26
|
-
set "zip7_install_path=%ProgramFiles%\7-Zip"
|
|
27
|
-
set "zip7_download_path=%TEMP%\%zip7version%.exe"
|
|
28
|
-
|
|
29
|
-
REM Environment Variables (TOOLBOX FFmpeg)
|
|
30
|
-
set "ffmpeg_url=https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z"
|
|
31
|
-
set "ffdownload_path=%TEMP%\ffmpeg.7z"
|
|
32
|
-
set "ffextract_path=C:\ffmpeg"
|
|
33
|
-
set "bin_path=%ffextract_path%\bin"
|
|
34
|
-
|
|
35
|
-
REM Environment Variables (TOOLBOX Node.js)
|
|
36
|
-
set "node_installer_path=%temp%\NodejsInstaller.msi"
|
|
37
|
-
|
|
38
|
-
REM Environment Variables (winget)
|
|
39
|
-
set "winget_path=%userprofile%\AppData\Local\Microsoft\WindowsApps"
|
|
40
|
-
|
|
41
|
-
REM Environment Variables (TOOLBOX Install Extras)
|
|
42
|
-
set "miniconda_path=%userprofile%\miniconda"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
REM Check if Winget is installed; if not, then install it
|
|
46
|
-
winget --version > nul 2>&1
|
|
47
|
-
if %errorlevel% neq 0 (
|
|
48
|
-
echo %yellow_fg_strong%[WARN] Winget is not installed on this system.
|
|
49
|
-
echo %blue_fg_strong%[INFO]%reset% Installing Winget...
|
|
50
|
-
bitsadmin /transfer "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe" /download /priority FOREGROUND "https://github.com/microsoft/winget-cli/releases/download/v1.5.2201/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" "%temp%\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
|
|
51
|
-
start "" "%temp%\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
|
|
52
|
-
echo %green_fg_strong%Winget is now installed.%reset%
|
|
53
|
-
) else (
|
|
54
|
-
echo %blue_fg_strong%[INFO] Winget is already installed.%reset%
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
rem Get the current PATH value from the registry
|
|
58
|
-
for /f "tokens=2*" %%A in ('reg query "HKCU\Environment" /v PATH') do set "current_path=%%B"
|
|
59
|
-
|
|
60
|
-
rem Check if the paths are already in the current PATH
|
|
61
|
-
echo %current_path% | find /i "%winget_path%" > nul
|
|
62
|
-
set "ff_path_exists=%errorlevel%"
|
|
63
|
-
|
|
64
|
-
rem Append the new paths to the current PATH only if they don't exist
|
|
65
|
-
if %ff_path_exists% neq 0 (
|
|
66
|
-
set "new_path=%current_path%;%winget_path%"
|
|
67
|
-
|
|
68
|
-
rem Update the PATH value in the registry
|
|
69
|
-
reg add "HKCU\Environment" /v PATH /t REG_EXPAND_SZ /d "%new_path%" /f
|
|
70
|
-
|
|
71
|
-
rem Update the PATH value for the current session
|
|
72
|
-
setx PATH "%new_path%" > nul
|
|
73
|
-
echo %green_fg_strong%winget added to PATH.%reset%
|
|
74
|
-
) else (
|
|
75
|
-
set "new_path=%current_path%"
|
|
76
|
-
echo %blue_fg_strong%[INFO] winget already exists in PATH.%reset%
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
REM Check if Git is installed if not then install git
|
|
81
|
-
git --version > nul 2>&1
|
|
82
|
-
if %errorlevel% neq 0 (
|
|
83
|
-
echo %yellow_fg_strong%[WARN] Git is not installed on this system.%reset%
|
|
84
|
-
echo %blue_fg_strong%[INFO]%reset% Installing Git using Winget...
|
|
85
|
-
winget install -e --id Git.Git
|
|
86
|
-
echo %green_fg_strong%Git is installed. Please restart the Launcher.%reset%
|
|
87
|
-
pause
|
|
88
|
-
exit
|
|
89
|
-
) else (
|
|
90
|
-
echo %blue_fg_strong%[INFO] Git is already installed.%reset%
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
REM Check for updates
|
|
94
|
-
git fetch origin
|
|
95
|
-
|
|
96
|
-
for /f %%i in ('git rev-list HEAD...origin/%current_branch%') do (
|
|
97
|
-
set "update_status=%yellow_fg_strong%Update Available%reset%"
|
|
98
|
-
goto :found_update
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
set "update_status=%green_fg_strong%Up to Date%reset%"
|
|
102
|
-
:found_update
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
REM Home - frontend
|
|
106
|
-
:home
|
|
107
|
-
cls
|
|
108
|
-
echo %blue_fg_strong%/ Home%reset%
|
|
109
|
-
echo -------------------------------------
|
|
110
|
-
echo What would you like to do?
|
|
111
|
-
echo 1. Start SillyTavern
|
|
112
|
-
echo 2. Start SillyTavern + Extras
|
|
113
|
-
echo 3. Update
|
|
114
|
-
echo 4. Backup
|
|
115
|
-
echo 5. Switch branch
|
|
116
|
-
echo 6. Toolbox
|
|
117
|
-
echo 7. Exit
|
|
118
|
-
|
|
119
|
-
REM Get the current Git branch
|
|
120
|
-
for /f %%i in ('git branch --show-current') do set current_branch=%%i
|
|
121
|
-
echo ======== VERSION STATUS =========
|
|
122
|
-
echo SillyTavern branch: %cyan_fg_strong%%current_branch%%reset%
|
|
123
|
-
echo Update Status: %update_status%
|
|
124
|
-
echo =================================
|
|
125
|
-
|
|
126
|
-
set "choice="
|
|
127
|
-
set /p "choice=Choose Your Destiny (default is 1): "
|
|
128
|
-
|
|
129
|
-
REM Default to choice 1 if no input is provided
|
|
130
|
-
if not defined choice set "choice=1"
|
|
131
|
-
|
|
132
|
-
REM Home - backend
|
|
133
|
-
if "%choice%"=="1" (
|
|
134
|
-
call :start
|
|
135
|
-
) else if "%choice%"=="2" (
|
|
136
|
-
call :start_extras
|
|
137
|
-
) else if "%choice%"=="3" (
|
|
138
|
-
call :update
|
|
139
|
-
) else if "%choice%"=="4" (
|
|
140
|
-
call :backup_menu
|
|
141
|
-
) else if "%choice%"=="5" (
|
|
142
|
-
call :switchbrance_menu
|
|
143
|
-
) else if "%choice%"=="6" (
|
|
144
|
-
call :toolbox
|
|
145
|
-
) else if "%choice%"=="7" (
|
|
146
|
-
exit
|
|
147
|
-
) else (
|
|
148
|
-
color 6
|
|
149
|
-
echo WARNING: Invalid number. Please insert a valid number.
|
|
150
|
-
pause
|
|
151
|
-
goto :home
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
:start
|
|
156
|
-
REM Check if Node.js is installed
|
|
157
|
-
node --version > nul 2>&1
|
|
158
|
-
if %errorlevel% neq 0 (
|
|
159
|
-
echo %red_fg_strong%[ERROR] node command not found in PATH%reset%
|
|
160
|
-
echo %red_bg%Please make sure Node.js is installed and added to your PATH.%reset%
|
|
161
|
-
echo %blue_bg%To install Node.js go to Toolbox%reset%
|
|
162
|
-
pause
|
|
163
|
-
goto :home
|
|
164
|
-
)
|
|
165
|
-
echo %blue_fg_strong%[INFO]%reset% A new window has been launched.
|
|
166
|
-
start /wait cmd /c start.bat
|
|
167
|
-
goto :home
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
:start_extras
|
|
171
|
-
REM Run conda activate from the Miniconda installation
|
|
172
|
-
call "%miniconda_path%\Scripts\activate.bat"
|
|
173
|
-
|
|
174
|
-
REM Activate the sillytavernextras environment
|
|
175
|
-
call conda activate sillytavernextras
|
|
176
|
-
|
|
177
|
-
REM Start SillyTavern Extras with desired configurations
|
|
178
|
-
python server.py --coqui-gpu --rvc-save-file --cuda-device=0 --max-content-length=1000 --enable-modules=caption,summarize,classify,rvc,coqui-tts --classification-model=joeddav/distilbert-base-uncased-go-emotions-student --share
|
|
179
|
-
goto :home
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
:update
|
|
183
|
-
echo Updating...
|
|
184
|
-
pushd %~dp0
|
|
185
|
-
REM Check if git is installed
|
|
186
|
-
git --version > nul 2>&1
|
|
187
|
-
if %errorlevel% neq 0 (
|
|
188
|
-
echo %red_fg_strong%[ERROR] git command not found in PATH. Skipping update.%reset%
|
|
189
|
-
echo %red_bg%Please make sure Git is installed and added to your PATH.%reset%
|
|
190
|
-
echo %blue_bg%To install Git go to Toolbox%reset%
|
|
191
|
-
) else (
|
|
192
|
-
call git pull --rebase --autostash
|
|
193
|
-
if %errorlevel% neq 0 (
|
|
194
|
-
REM incase there is still something wrong
|
|
195
|
-
echo There were errors while updating. Please download the latest version manually.
|
|
196
|
-
)
|
|
197
|
-
)
|
|
198
|
-
pause
|
|
199
|
-
goto :home
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
REM Switch Brance - frontend
|
|
203
|
-
:switchbrance_menu
|
|
204
|
-
cls
|
|
205
|
-
echo %blue_fg_strong%/ Home / Switch Branch%reset%
|
|
206
|
-
echo -------------------------------------
|
|
207
|
-
echo What would you like to do?
|
|
208
|
-
echo 1. Switch to Release - SillyTavern
|
|
209
|
-
echo 2. Switch to Staging - SillyTavern
|
|
210
|
-
echo 3. Switch to Main - Extras
|
|
211
|
-
echo 4. Switch to Neo - Extras
|
|
212
|
-
echo 5. Back to Home
|
|
213
|
-
|
|
214
|
-
REM Get the current Git branch
|
|
215
|
-
for /f %%i in ('git branch --show-current') do set current_branch=%%i
|
|
216
|
-
echo ======== VERSION STATUS =========
|
|
217
|
-
echo SillyTavern branch: %cyan_fg_strong%%current_branch%%reset%
|
|
218
|
-
echo Extras branch: %cyan_fg_strong%%current_branch%%reset%
|
|
219
|
-
echo =================================
|
|
220
|
-
set /p brance_choice=Choose Your Destiny:
|
|
221
|
-
|
|
222
|
-
REM Switch Brance - backend
|
|
223
|
-
if "%brance_choice%"=="1" (
|
|
224
|
-
call :switch_release_st
|
|
225
|
-
) else if "%brance_choice%"=="2" (
|
|
226
|
-
call :switch_staging_st
|
|
227
|
-
) else if "%brance_choice%"=="3" (
|
|
228
|
-
call :switch_main_ste
|
|
229
|
-
) else if "%brance_choice%"=="4" (
|
|
230
|
-
call :switch_neo_ste
|
|
231
|
-
) else if "%brance_choice%"=="5" (
|
|
232
|
-
goto :home
|
|
233
|
-
) else (
|
|
234
|
-
color 6
|
|
235
|
-
echo WARNING: Invalid number. Please insert a valid number.
|
|
236
|
-
pause
|
|
237
|
-
goto :switchbrance_menu
|
|
238
|
-
)
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
:switch_release_st
|
|
242
|
-
echo %blue_fg_strong%[INFO]%reset% Switching to release branch...
|
|
243
|
-
git switch release
|
|
244
|
-
pause
|
|
245
|
-
goto :switchbrance_menu
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
:switch_staging_st
|
|
249
|
-
echo %blue_fg_strong%[INFO]%reset% Switching to staging branch...
|
|
250
|
-
git switch staging
|
|
251
|
-
pause
|
|
252
|
-
goto :switchbrance_menu
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
:switch_main_ste
|
|
256
|
-
echo %blue_fg_strong%[INFO]%reset% Switching to main branch...
|
|
257
|
-
cd SillyTavern-extras
|
|
258
|
-
git switch main
|
|
259
|
-
pause
|
|
260
|
-
goto :switchbrance_menu
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
:switch_neo_ste
|
|
264
|
-
echo %blue_fg_strong%[INFO]%reset% Switching to neo branch...
|
|
265
|
-
cd SillyTavern-extras
|
|
266
|
-
git switch neo
|
|
267
|
-
pause
|
|
268
|
-
goto :switchbrance_menu
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
REM Backup - Frontend
|
|
272
|
-
:backup_menu
|
|
273
|
-
REM Check if 7-Zip is installed
|
|
274
|
-
7z > nul 2>&1
|
|
275
|
-
if %errorlevel% neq 0 (
|
|
276
|
-
echo %red_fg_strong%[ERROR] 7z command not found in PATH%reset%
|
|
277
|
-
echo %red_bg%Please make sure 7-Zip is installed and added to your PATH.%reset%
|
|
278
|
-
echo %blue_bg%To install 7-Zip go to Toolbox%reset%
|
|
279
|
-
pause
|
|
280
|
-
goto :home
|
|
281
|
-
)
|
|
282
|
-
cls
|
|
283
|
-
echo %blue_fg_strong%/ Home / Backup%reset%
|
|
284
|
-
echo -------------------------------------
|
|
285
|
-
echo What would you like to do?
|
|
286
|
-
REM color 7
|
|
287
|
-
echo 1. Create Backup
|
|
288
|
-
echo 2. Restore Backup
|
|
289
|
-
echo 3. Back to Home
|
|
290
|
-
|
|
291
|
-
set /p backup_choice=Choose Your Destiny:
|
|
292
|
-
|
|
293
|
-
REM Backup - Backend
|
|
294
|
-
if "%backup_choice%"=="1" (
|
|
295
|
-
call :create_backup
|
|
296
|
-
) else if "%backup_choice%"=="2" (
|
|
297
|
-
call :restore_backup
|
|
298
|
-
) else if "%backup_choice%"=="3" (
|
|
299
|
-
goto :home
|
|
300
|
-
) else (
|
|
301
|
-
color 6
|
|
302
|
-
echo WARNING: Invalid number. Please insert a valid number.
|
|
303
|
-
pause
|
|
304
|
-
goto :backup_menu
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
:create_backup
|
|
308
|
-
REM Create a backup using 7zip
|
|
309
|
-
7z a "backups\backup_.7z" ^
|
|
310
|
-
"public\assets\*" ^
|
|
311
|
-
"public\Backgrounds\*" ^
|
|
312
|
-
"public\Characters\*" ^
|
|
313
|
-
"public\Chats\*" ^
|
|
314
|
-
"public\context\*" ^
|
|
315
|
-
"public\Group chats\*" ^
|
|
316
|
-
"public\Groups\*" ^
|
|
317
|
-
"public\instruct\*" ^
|
|
318
|
-
"public\KoboldAI Settings\*" ^
|
|
319
|
-
"public\movingUI\*" ^
|
|
320
|
-
"public\NovelAI Settings\*" ^
|
|
321
|
-
"public\OpenAI Settings\*" ^
|
|
322
|
-
"public\QuickReplies\*" ^
|
|
323
|
-
"public\TextGen Settings\*" ^
|
|
324
|
-
"public\themes\*" ^
|
|
325
|
-
"public\User Avatars\*" ^
|
|
326
|
-
"public\user\*" ^
|
|
327
|
-
"public\worlds\*" ^
|
|
328
|
-
"public\settings.json" ^
|
|
329
|
-
"secrets.json"
|
|
330
|
-
|
|
331
|
-
REM Get current date and time components
|
|
332
|
-
for /f "tokens=1-3 delims=/- " %%d in ("%date%") do (
|
|
333
|
-
set "day=%%d"
|
|
334
|
-
set "month=%%e"
|
|
335
|
-
set "year=%%f"
|
|
336
|
-
)
|
|
337
|
-
|
|
338
|
-
for /f "tokens=1-2 delims=:." %%h in ("%time%") do (
|
|
339
|
-
set "hour=%%h"
|
|
340
|
-
set "minute=%%i"
|
|
341
|
-
)
|
|
342
|
-
|
|
343
|
-
REM Pad single digits with leading zeros
|
|
344
|
-
setlocal enabledelayedexpansion
|
|
345
|
-
set "day=0!day!"
|
|
346
|
-
set "month=0!month!"
|
|
347
|
-
set "hour=0!hour!"
|
|
348
|
-
set "minute=0!minute!"
|
|
349
|
-
|
|
350
|
-
set "formatted_date=%month:~-2%-%day:~-2%-%year%_%hour:~-2%%minute:~-2%"
|
|
351
|
-
|
|
352
|
-
REM Rename the backup file with the formatted date and time
|
|
353
|
-
rename "backups\backup_.7z" "backup_%formatted_date%.7z"
|
|
354
|
-
|
|
355
|
-
endlocal
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
echo %green_fg_strong%Backup created successfully!%reset%
|
|
359
|
-
pause
|
|
360
|
-
endlocal
|
|
361
|
-
goto :backup_menu
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
:restore_backup
|
|
365
|
-
REM Restore a backup using 7zip
|
|
366
|
-
|
|
367
|
-
echo List of available backups:
|
|
368
|
-
echo =========================
|
|
369
|
-
|
|
370
|
-
setlocal enabledelayedexpansion
|
|
371
|
-
set "backup_count=0"
|
|
372
|
-
|
|
373
|
-
for %%F in ("backups\backup_*.7z") do (
|
|
374
|
-
set /a "backup_count+=1"
|
|
375
|
-
set "backup_files[!backup_count!]=%%~nF"
|
|
376
|
-
echo !backup_count!. %cyan_fg_strong%%%~nF%reset%
|
|
377
|
-
)
|
|
378
|
-
|
|
379
|
-
echo =========================
|
|
380
|
-
set /p "restore_choice=Enter number of backup to restore: "
|
|
381
|
-
|
|
382
|
-
if "%restore_choice%" geq "1" (
|
|
383
|
-
if "%restore_choice%" leq "%backup_count%" (
|
|
384
|
-
set "selected_backup=!backup_files[%restore_choice%]!"
|
|
385
|
-
echo Restoring backup !selected_backup!...
|
|
386
|
-
REM Extract the contents of the "public" folder directly into the existing "public" folder
|
|
387
|
-
7z x "backups\!selected_backup!.7z" -o"temp" -aoa
|
|
388
|
-
xcopy /y /e "temp\public\*" "public\"
|
|
389
|
-
rmdir /s /q "temp"
|
|
390
|
-
echo %green_fg_strong%!selected_backup! restored successfully.%reset%
|
|
391
|
-
) else (
|
|
392
|
-
color 6
|
|
393
|
-
echo WARNING: Invalid backup number. Please insert a valid number.
|
|
394
|
-
)
|
|
395
|
-
) else (
|
|
396
|
-
color 6
|
|
397
|
-
echo WARNING: Invalid number. Please insert a valid number.
|
|
398
|
-
)
|
|
399
|
-
pause
|
|
400
|
-
goto :backup_menu
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
REM Toolbox - Frontend
|
|
404
|
-
:toolbox
|
|
405
|
-
cls
|
|
406
|
-
echo %blue_fg_strong%/ Home / Toolbox%reset%
|
|
407
|
-
echo -------------------------------------
|
|
408
|
-
echo What would you like to do?
|
|
409
|
-
REM color 7
|
|
410
|
-
echo 1. Install 7-Zip
|
|
411
|
-
echo 2. Install FFmpeg
|
|
412
|
-
echo 3. Install Node.js
|
|
413
|
-
echo 4. Edit Environment
|
|
414
|
-
echo 5. Reinstall SillyTavern
|
|
415
|
-
echo 6. Reinstall Extras
|
|
416
|
-
echo 7. Back to Home
|
|
417
|
-
|
|
418
|
-
set /p toolbox_choice=Choose Your Destiny:
|
|
419
|
-
|
|
420
|
-
REM Toolbox - Backend
|
|
421
|
-
if "%toolbox_choice%"=="1" (
|
|
422
|
-
call :install7zip
|
|
423
|
-
) else if "%toolbox_choice%"=="2" (
|
|
424
|
-
call :installffmpeg
|
|
425
|
-
) else if "%toolbox_choice%"=="3" (
|
|
426
|
-
call :installnodejs
|
|
427
|
-
) else if "%toolbox_choice%"=="4" (
|
|
428
|
-
call :editenvironment
|
|
429
|
-
) else if "%toolbox_choice%"=="5" (
|
|
430
|
-
call :reinstallsillytavern
|
|
431
|
-
) else if "%toolbox_choice%"=="6" (
|
|
432
|
-
call :reinstallextras
|
|
433
|
-
) else if "%toolbox_choice%"=="7" (
|
|
434
|
-
goto :home
|
|
435
|
-
) else (
|
|
436
|
-
color 6
|
|
437
|
-
echo WARNING: Invalid number. Please insert a valid number.
|
|
438
|
-
pause
|
|
439
|
-
goto :toolbox
|
|
440
|
-
)
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
:install7zip
|
|
444
|
-
echo %blue_fg_strong%[INFO]%reset% Installing 7-Zip...
|
|
445
|
-
winget install -e --id 7zip.7zip
|
|
446
|
-
|
|
447
|
-
rem Get the current PATH value from the registry
|
|
448
|
-
for /f "tokens=2*" %%A in ('reg query "HKCU\Environment" /v PATH') do set "current_path=%%B"
|
|
449
|
-
|
|
450
|
-
rem Check if the paths are already in the current PATH
|
|
451
|
-
echo %current_path% | find /i "%zip7_install_path%" > nul
|
|
452
|
-
set "zip7_path_exists=%errorlevel%"
|
|
453
|
-
|
|
454
|
-
rem Append the new paths to the current PATH only if they don't exist
|
|
455
|
-
if %zip7_path_exists% neq 0 (
|
|
456
|
-
set "new_path=%current_path%;%zip7_install_path%"
|
|
457
|
-
echo %green_fg_strong%7-Zip added to PATH.%reset%
|
|
458
|
-
) else (
|
|
459
|
-
set "new_path=%current_path%"
|
|
460
|
-
echo %blue_fg_strong%[INFO] 7-Zip already exists in PATH.%reset%
|
|
461
|
-
)
|
|
462
|
-
|
|
463
|
-
rem Update the PATH value in the registry
|
|
464
|
-
reg add "HKCU\Environment" /v PATH /t REG_EXPAND_SZ /d "%new_path%" /f
|
|
465
|
-
|
|
466
|
-
rem Update the PATH value for the current session
|
|
467
|
-
setx PATH "%new_path%"
|
|
468
|
-
|
|
469
|
-
echo %green_fg_strong%7-Zip is installed. Please restart the Launcher.%reset%
|
|
470
|
-
pause
|
|
471
|
-
exit
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
:installffmpeg
|
|
475
|
-
REM Check if 7-Zip is installed
|
|
476
|
-
7z > nul 2>&1
|
|
477
|
-
if %errorlevel% neq 0 (
|
|
478
|
-
echo %red_fg_strong%[ERROR] 7z command not found in PATH%reset%
|
|
479
|
-
echo %red_bg%Please make sure 7-Zip is installed and added to your PATH.%reset%
|
|
480
|
-
echo %blue_bg%To install 7-Zip go to Toolbox%reset%
|
|
481
|
-
pause
|
|
482
|
-
goto :toolbox
|
|
483
|
-
)
|
|
484
|
-
|
|
485
|
-
echo %blue_fg_strong%[INFO]%reset% Downloading FFmpeg archive...
|
|
486
|
-
rem bitsadmin /transfer "ffmpeg" /download /priority FOREGROUND "%ffmpeg_url%" "%ffdownload_path%"
|
|
487
|
-
curl -o "%ffdownload_path%" "%ffmpeg_url%"
|
|
488
|
-
|
|
489
|
-
echo %blue_fg_strong%[INFO]%reset% Creating ffmpeg directory if it doesn't exist...
|
|
490
|
-
if not exist "%ffextract_path%" (
|
|
491
|
-
mkdir "%ffextract_path%"
|
|
492
|
-
)
|
|
493
|
-
|
|
494
|
-
echo %blue_fg_strong%[INFO]%reset% Extracting FFmpeg archive...
|
|
495
|
-
7z x "%ffdownload_path%" -o"%ffextract_path%"
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
echo %blue_fg_strong%[INFO]%reset% Moving FFmpeg contents to C:\ffmpeg...
|
|
499
|
-
for /d %%i in ("%ffextract_path%\ffmpeg-*-full_build") do (
|
|
500
|
-
xcopy "%%i\bin" "%ffextract_path%\bin" /E /I /Y
|
|
501
|
-
xcopy "%%i\doc" "%ffextract_path%\doc" /E /I /Y
|
|
502
|
-
xcopy "%%i\presets" "%ffextract_path%\presets" /E /I /Y
|
|
503
|
-
rd "%%i" /S /Q
|
|
504
|
-
)
|
|
505
|
-
|
|
506
|
-
rem Get the current PATH value from the registry
|
|
507
|
-
for /f "tokens=2*" %%A in ('reg query "HKCU\Environment" /v PATH') do set "current_path=%%B"
|
|
508
|
-
|
|
509
|
-
rem Check if the paths are already in the current PATH
|
|
510
|
-
echo %current_path% | find /i "%bin_path%" > nul
|
|
511
|
-
set "ff_path_exists=%errorlevel%"
|
|
512
|
-
|
|
513
|
-
rem Append the new paths to the current PATH only if they don't exist
|
|
514
|
-
if %ff_path_exists% neq 0 (
|
|
515
|
-
set "new_path=%current_path%;%bin_path%"
|
|
516
|
-
echo %green_fg_strong%ffmpeg added to PATH.%reset%
|
|
517
|
-
) else (
|
|
518
|
-
set "new_path=%current_path%"
|
|
519
|
-
echo %blue_fg_strong%[INFO] ffmpeg already exists in PATH.%reset%
|
|
520
|
-
)
|
|
521
|
-
|
|
522
|
-
rem Update the PATH value in the registry
|
|
523
|
-
reg add "HKCU\Environment" /v PATH /t REG_EXPAND_SZ /d "%new_path%" /f
|
|
524
|
-
|
|
525
|
-
rem Update the PATH value for the current session
|
|
526
|
-
setx PATH "%new_path%" > nul
|
|
527
|
-
|
|
528
|
-
del "%ffdownload_path%"
|
|
529
|
-
echo %green_fg_strong%FFmpeg is installed. Please restart the Launcher.%reset%
|
|
530
|
-
pause
|
|
531
|
-
exit
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
:installnodejs
|
|
535
|
-
echo %blue_fg_strong%[INFO]%reset% Installing Node.js...
|
|
536
|
-
winget install -e --id OpenJS.NodeJS
|
|
537
|
-
echo %green_fg_strong%Node.js is installed. Please restart the Launcher.%reset%
|
|
538
|
-
pause
|
|
539
|
-
exit
|
|
540
|
-
|
|
541
|
-
:editenvironment
|
|
542
|
-
rundll32.exe sysdm.cpl,EditEnvironmentVariables
|
|
543
|
-
goto :toolbox
|
|
544
|
-
|
|
545
|
-
:reinstallsillytavern
|
|
546
|
-
setlocal enabledelayedexpansion
|
|
547
|
-
chcp 65001 > nul
|
|
548
|
-
REM Define the names of items to be excluded
|
|
549
|
-
set "script_name=%~nx0"
|
|
550
|
-
set "excluded_folders=backups"
|
|
551
|
-
set "excluded_files=!script_name!"
|
|
552
|
-
|
|
553
|
-
REM Confirm with the user before proceeding
|
|
554
|
-
echo.
|
|
555
|
-
echo %red_bg%╔════ DANGER ZONE ══════════════════════════════════════════════════════════════════════════════╗%reset%
|
|
556
|
-
echo %red_bg%║ WARNING: This will delete all data in the current branch except the Backups. ║%reset%
|
|
557
|
-
echo %red_bg%║ If you want to keep any data, make sure to create a backup before proceeding. ║%reset%
|
|
558
|
-
echo %red_bg%╚═══════════════════════════════════════════════════════════════════════════════════════════════╝%reset%
|
|
559
|
-
echo.
|
|
560
|
-
echo Are you sure you want to proceed? [Y/N]
|
|
561
|
-
set /p "confirmation="
|
|
562
|
-
if /i "!confirmation!"=="Y" (
|
|
563
|
-
REM Remove non-excluded folders
|
|
564
|
-
for /d %%D in (*) do (
|
|
565
|
-
set "exclude_folder="
|
|
566
|
-
for %%E in (!excluded_folders!) do (
|
|
567
|
-
if "%%D"=="%%E" set "exclude_folder=true"
|
|
568
|
-
)
|
|
569
|
-
if not defined exclude_folder (
|
|
570
|
-
rmdir /s /q "%%D" 2>nul
|
|
571
|
-
)
|
|
572
|
-
)
|
|
573
|
-
|
|
574
|
-
REM Remove non-excluded files
|
|
575
|
-
for %%F in (*) do (
|
|
576
|
-
set "exclude_file="
|
|
577
|
-
for %%E in (!excluded_files!) do (
|
|
578
|
-
if "%%F"=="%%E" set "exclude_file=true"
|
|
579
|
-
)
|
|
580
|
-
if not defined exclude_file (
|
|
581
|
-
del /f /q "%%F" 2>nul
|
|
582
|
-
)
|
|
583
|
-
)
|
|
584
|
-
|
|
585
|
-
REM Clone repo into %temp% folder
|
|
586
|
-
git clone https://github.com/SillyTavern/SillyTavern.git "%temp%\SillyTavernTemp"
|
|
587
|
-
|
|
588
|
-
REM Move the contents of the temporary folder to the current directory
|
|
589
|
-
xcopy /e /y "%temp%\SillyTavernTemp\*" .
|
|
590
|
-
|
|
591
|
-
REM Clean up the temporary folder
|
|
592
|
-
rmdir /s /q "%temp%\SillyTavernTemp"
|
|
593
|
-
|
|
594
|
-
echo %green_fg_strong%SillyTavern reinstalled successfully!%reset%
|
|
595
|
-
) else (
|
|
596
|
-
echo Reinstall canceled.
|
|
597
|
-
)
|
|
598
|
-
endlocal
|
|
599
|
-
pause
|
|
600
|
-
goto :toolbox
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
:reinstallextras
|
|
604
|
-
cls
|
|
605
|
-
echo %blue_fg_strong%SillyTavern Extras%reset%
|
|
606
|
-
echo ---------------------------------------------------------------
|
|
607
|
-
echo %blue_fg_strong%[INFO]%reset% Installing SillyTavern Extras...
|
|
608
|
-
echo --------------------------------
|
|
609
|
-
echo %cyan_fg_strong%This may take a while. Please be patient.%reset%
|
|
610
|
-
|
|
611
|
-
winget install -e --id Anaconda.Miniconda3
|
|
612
|
-
|
|
613
|
-
REM Run conda activate from the Miniconda installation
|
|
614
|
-
call "%miniconda_path%\Scripts\activate.bat"
|
|
615
|
-
|
|
616
|
-
REM Create a Conda environment named sillytavernextras
|
|
617
|
-
call conda create -n sillytavernextras -y
|
|
618
|
-
|
|
619
|
-
REM Activate the sillytavernextras environment
|
|
620
|
-
call conda activate sillytavernextras
|
|
621
|
-
|
|
622
|
-
REM Install Python 3.11 and Git in the sillytavernextras environment
|
|
623
|
-
call conda install python=3.11 git -y
|
|
624
|
-
|
|
625
|
-
REM Clone the SillyTavern Extras repository
|
|
626
|
-
git clone https://github.com/SillyTavern/SillyTavern-extras
|
|
627
|
-
|
|
628
|
-
REM Navigate to the SillyTavern-extras directory
|
|
629
|
-
cd SillyTavern-extras
|
|
630
|
-
|
|
631
|
-
REM Install Python dependencies from requirements files
|
|
632
|
-
pip install -r requirements-complete.txt
|
|
633
|
-
pip install -r requirements-rvc.txt
|
|
634
|
-
|
|
635
|
-
REM Start SillyTavern Extras with desired configurations
|
|
636
|
-
python server.py --coqui-gpu --rvc-save-file --cuda-device=0 --max-content-length=1000 --enable-modules=caption,summarize,classify,rvc,coqui-tts --classification-model=joeddav/distilbert-base-uncased-go-emotions-student --share
|
|
637
|
-
|
|
638
|
-
echo.
|
|
639
|
-
echo %green_fg_strong%SillyTavern Extras have been successfully installed.%reset%
|
|
640
|
-
pause
|
|
641
|
-
goto :toolbox
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import jimp from 'jimp';
|
|
3
|
-
import extract from 'png-chunks-extract';
|
|
4
|
-
import encode from 'png-chunks-encode';
|
|
5
|
-
import PNGtext from 'png-chunk-text';
|
|
6
|
-
import ExifReader from 'exifreader';
|
|
7
|
-
import webp from 'webp-converter';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
|
|
10
|
-
async function charaRead(img_url, input_format){
|
|
11
|
-
let format;
|
|
12
|
-
if(input_format === undefined){
|
|
13
|
-
if(img_url.indexOf('.webp') !== -1){
|
|
14
|
-
format = 'webp';
|
|
15
|
-
}else{
|
|
16
|
-
format = 'png';
|
|
17
|
-
}
|
|
18
|
-
}else{
|
|
19
|
-
format = input_format;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
switch(format){
|
|
23
|
-
case 'webp':
|
|
24
|
-
const exif_data = await ExifReader.load(fs.readFileSync(img_url));
|
|
25
|
-
const char_data = exif_data['UserComment']['description'];
|
|
26
|
-
if (char_data === 'Undefined' && exif_data['UserComment'].value && exif_data['UserComment'].value.length === 1) {
|
|
27
|
-
return exif_data['UserComment'].value[0];
|
|
28
|
-
}
|
|
29
|
-
return char_data;
|
|
30
|
-
case 'png':
|
|
31
|
-
const buffer = fs.readFileSync(img_url);
|
|
32
|
-
const chunks = extract(buffer);
|
|
33
|
-
|
|
34
|
-
const textChunks = chunks.filter(function (chunk) {
|
|
35
|
-
return chunk.name === 'tEXt';
|
|
36
|
-
}).map(function (chunk) {
|
|
37
|
-
//console.log(text.decode(chunk.data));
|
|
38
|
-
return PNGtext.decode(chunk.data);
|
|
39
|
-
});
|
|
40
|
-
var base64DecodedData = Buffer.from(textChunks[0].text, 'base64').toString('utf8');
|
|
41
|
-
return base64DecodedData;//textChunks[0].text;
|
|
42
|
-
//console.log(textChunks[0].keyword); // 'hello'
|
|
43
|
-
//console.log(textChunks[0].text); // 'world'
|
|
44
|
-
default:
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function charaWrite(img_url, data, target_img, response = undefined, mes = 'ok') {
|
|
51
|
-
try {
|
|
52
|
-
// Read the image, resize, and save it as a PNG into the buffer
|
|
53
|
-
|
|
54
|
-
webp
|
|
55
|
-
|
|
56
|
-
const rawImg = await jimp.read(img_url);
|
|
57
|
-
const image = await rawImg.cover(400, 600).getBufferAsync(jimp.MIME_PNG);
|
|
58
|
-
|
|
59
|
-
// Get the chunks
|
|
60
|
-
const chunks = extract(image);
|
|
61
|
-
const tEXtChunks = chunks.filter(chunk => chunk.create_date === 'tEXt');
|
|
62
|
-
|
|
63
|
-
// Remove all existing tEXt chunks
|
|
64
|
-
for (let tEXtChunk of tEXtChunks) {
|
|
65
|
-
chunks.splice(chunks.indexOf(tEXtChunk), 1);
|
|
66
|
-
}
|
|
67
|
-
// Add new chunks before the IEND chunk
|
|
68
|
-
const base64EncodedData = Buffer.from(data, 'utf8').toString('base64');
|
|
69
|
-
chunks.splice(-1, 0, PNGtext.encode('chara', base64EncodedData));
|
|
70
|
-
//chunks.splice(-1, 0, text.encode('lorem', 'ipsum'));
|
|
71
|
-
|
|
72
|
-
fs.writeFileSync(target_img, new Buffer.from(encode(chunks)));
|
|
73
|
-
if (response !== undefined) response.send(mes);
|
|
74
|
-
return true;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
} catch (err) {
|
|
78
|
-
console.log(err);
|
|
79
|
-
if (response !== undefined) response.status(500).send(err);
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
(async function() {
|
|
86
|
-
const spath = process.argv[2]
|
|
87
|
-
const dpath = process.argv[3] || spath
|
|
88
|
-
const files = fs.readdirSync(spath).filter(e => e.endsWith(".webp"))
|
|
89
|
-
if (!files.length) {
|
|
90
|
-
console.log("Nothing to convert.")
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
try { fs.mkdirSync(dpath) } catch {}
|
|
95
|
-
|
|
96
|
-
for(const f of files) {
|
|
97
|
-
const source = path.join(spath, f),
|
|
98
|
-
dest = path.join(dpath, path.basename(f, ".webp") + ".png")
|
|
99
|
-
|
|
100
|
-
console.log(`Read... ${source}`)
|
|
101
|
-
const data = await charaRead(source)
|
|
102
|
-
|
|
103
|
-
console.log(`Convert... ${source} -> ${dest}`)
|
|
104
|
-
await webp.dwebp(source, dest, "-o")
|
|
105
|
-
|
|
106
|
-
console.log(`Write... ${dest}`)
|
|
107
|
-
const success = await charaWrite(dest, data, path.parse(dest).name);
|
|
108
|
-
|
|
109
|
-
if (!success) {
|
|
110
|
-
console.log(`Failure on ${source} -> ${dest}`);
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
console.log(`Remove... ${source}`)
|
|
115
|
-
fs.rmSync(source)
|
|
116
|
-
}
|
|
117
|
-
})()
|