mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2bbc40a796 | ||
|
0c55d36a2b | ||
|
29e0a8335b | ||
|
084d17dc19 | ||
|
3b99f7839b | ||
|
7c6c2ee8b6 | ||
|
c873a6b04c | ||
|
d4332aa7ec | ||
|
267db5166f | ||
|
0e45450912 | ||
|
a37922ad59 | ||
|
e4a6bdb389 | ||
|
a43f99b492 | ||
|
c890da2877 | ||
|
bec6227aaf | ||
|
6a2a0efc84 | ||
|
b09ea054df | ||
|
024784e0b0 | ||
|
329158349f | ||
|
62d5f20590 | ||
|
e420c96e77 | ||
|
7af5a6ee5d | ||
|
e91cbe009f |
1
.github/readme.md
vendored
1
.github/readme.md
vendored
@@ -293,6 +293,7 @@ GNU Affero General Public License for more details.**
|
||||
* Cohee's modifications and derived code: AGPL v3
|
||||
* RossAscends' additions: AGPL v3
|
||||
* Portions of CncAnon's TavernAITurbo mod: Unknown license
|
||||
* BlipRanger's miscellaneous UI & extension modifications (<https://github.com/BlipRanger>)
|
||||
* Waifu mode inspired by the work of PepperTaco (<https://github.com/peppertaco/Tavern/>)
|
||||
* Thanks Pygmalion University for being awesome testers and suggesting cool features!
|
||||
* Thanks oobabooga for compiling presets for TextGen
|
||||
|
@@ -1,5 +1,5 @@
|
||||
pushd %~dp0
|
||||
call npm install
|
||||
call npm install --no-audit
|
||||
node server.js
|
||||
pause
|
||||
popd
|
||||
popd
|
||||
|
10
package-lock.json
generated
10
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "sillytavern",
|
||||
"version": "1.7.0",
|
||||
"version": "1.7.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sillytavern",
|
||||
"version": "1.7.0",
|
||||
"version": "1.7.3",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@dqbd/tiktoken": "^1.0.2",
|
||||
@@ -3035,9 +3035,9 @@
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.5.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz",
|
||||
"integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==",
|
||||
"version": "7.5.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
|
||||
"integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
|
@@ -48,7 +48,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/SillyTavern/SillyTavern.git"
|
||||
},
|
||||
"version": "1.7.0",
|
||||
"version": "1.7.3",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"pkg": "pkg --compress Gzip --no-bytecode --public ."
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"order": [1, 0, 3]
|
||||
"order": [1, 0, 3],
|
||||
"temperature": 1.07,
|
||||
"max_length": 60,
|
||||
"min_length": 60,
|
||||
@@ -14,4 +14,4 @@
|
||||
"repetition_penalty_frequency": 0,
|
||||
"repetition_penalty_presence": 0,
|
||||
"max_context":2048
|
||||
}
|
||||
}
|
||||
|
@@ -2279,7 +2279,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
|
||||
if (preset_settings != 'gui') {
|
||||
const maxContext = (adjustedParams && horde_settings.auto_adjust_context_length) ? adjustedParams.maxContextLength : max_context;
|
||||
generate_data = getKoboldGenerationData(finalPromt, this_settings, this_amount_gen, maxContext, isImpersonate);
|
||||
generate_data = getKoboldGenerationData(finalPromt, this_settings, this_amount_gen, maxContext, isImpersonate, type);
|
||||
}
|
||||
}
|
||||
else if (main_api == 'textgenerationwebui') {
|
||||
|
@@ -173,7 +173,7 @@ function resetTtsPlayback() {
|
||||
|
||||
// Reset audio element
|
||||
audioElement.currentTime = 0;
|
||||
audioElement.src = '/sounds/silence.mp3';
|
||||
audioElement.src = '';
|
||||
|
||||
// Clear any queue items
|
||||
ttsJobQueue.splice(0, ttsJobQueue.length);
|
||||
@@ -412,7 +412,6 @@ async function processTtsQueue() {
|
||||
|
||||
// Remove character name from start of the line if power user setting is disabled
|
||||
if (char && !power_user.allow_name2_display) {
|
||||
debugger;
|
||||
const escapedChar = escapeRegex(char);
|
||||
text = text.replace(new RegExp(`^${escapedChar}:`, 'gm'), '');
|
||||
}
|
||||
@@ -704,26 +703,4 @@ $(document).ready(function () {
|
||||
const wrapper = new ModuleWorkerWrapper(moduleWorker);
|
||||
setInterval(wrapper.update.bind(wrapper), UPDATE_INTERVAL) // Init depends on all the things
|
||||
eventSource.on(event_types.MESSAGE_SWIPED, resetTtsPlayback);
|
||||
|
||||
// Mobiles need to "activate" the Audio element with click before it can be played
|
||||
if (isMobile()) {
|
||||
console.debug('Activating mobile audio element on first click');
|
||||
let audioActivated = false;
|
||||
|
||||
// Play silence on first click
|
||||
$(document).on('click touchend', function () {
|
||||
// Prevent multiple activations
|
||||
if (audioActivated) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('Activating audio element...');
|
||||
audioActivated = true;
|
||||
audioElement.src = '/sounds/silence.mp3';
|
||||
// Reset volume to 1
|
||||
audioElement.onended = function () {
|
||||
console.debug('Audio element activated');
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
|
@@ -68,7 +68,7 @@ function loadKoboldSettings(preset) {
|
||||
}
|
||||
}
|
||||
|
||||
function getKoboldGenerationData(finalPromt, this_settings, this_amount_gen, this_max_context, isImpersonate) {
|
||||
function getKoboldGenerationData(finalPromt, this_settings, this_amount_gen, this_max_context, isImpersonate, type) {
|
||||
let generate_data = {
|
||||
prompt: finalPromt,
|
||||
gui_settings: false,
|
||||
@@ -94,7 +94,7 @@ function getKoboldGenerationData(finalPromt, this_settings, this_amount_gen, thi
|
||||
use_world_info: false,
|
||||
singleline: kai_settings.single_line,
|
||||
stop_sequence: kai_settings.use_stop_sequence ? getStoppingStrings(isImpersonate, false) : undefined,
|
||||
streaming: kai_settings.streaming_kobold && kai_settings.can_use_streaming,
|
||||
streaming: kai_settings.streaming_kobold && kai_settings.can_use_streaming && type !== 'quiet',
|
||||
can_abort: kai_settings.can_use_streaming,
|
||||
};
|
||||
return generate_data;
|
||||
@@ -213,7 +213,7 @@ function canUseKoboldStopSequence(version) {
|
||||
}
|
||||
|
||||
function canUseKoboldStreaming(koboldVersion) {
|
||||
if (koboldVersion.result == 'KoboldCpp') {
|
||||
if (koboldVersion && koboldVersion.result == 'KoboldCpp') {
|
||||
return (koboldVersion.version || '0.0').localeCompare(MIN_STREAMING_KCPPVERSION, undefined, { numeric: true, sensitivity: 'base' }) > -1;
|
||||
} else return false;
|
||||
}
|
||||
|
@@ -1490,10 +1490,11 @@ function onModelChange() {
|
||||
}
|
||||
else {
|
||||
$('#openai_max_context').attr('max', claude_max);
|
||||
oai_settings.openai_max_context = Math.max(oai_settings.openai_max_context, claude_max);
|
||||
$('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
|
||||
}
|
||||
|
||||
oai_settings.openai_max_context = Math.min(oai_settings.openai_max_context, Number($('#openai_max_context').attr('max')));
|
||||
$('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
|
||||
|
||||
$('#openai_reverse_proxy').attr('placeholder', 'https://api.anthropic.com/v1');
|
||||
|
||||
oai_settings.temp_openai = Math.min(claude_max_temp, oai_settings.temp_openai);
|
||||
@@ -1527,7 +1528,7 @@ function onModelChange() {
|
||||
$('#openai_max_context').attr('max', gpt3_max);
|
||||
}
|
||||
|
||||
oai_settings.openai_max_context = Math.max(Number($('#openai_max_context').val()), oai_settings.openai_max_context);
|
||||
oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context);
|
||||
$('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
|
||||
|
||||
if (value.includes('claude')) {
|
||||
@@ -1557,7 +1558,7 @@ function onModelChange() {
|
||||
$('#openai_max_context').attr('max', gpt3_max);
|
||||
}
|
||||
|
||||
oai_settings.openai_max_context = Math.max(oai_settings.openai_max_context, Number($('#openai_max_context').attr('max')));
|
||||
oai_settings.openai_max_context = Math.min(oai_settings.openai_max_context, Number($('#openai_max_context').attr('max')));
|
||||
$('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
|
||||
|
||||
$('#openai_reverse_proxy').attr('placeholder', 'https://api.openai.com/v1');
|
||||
|
@@ -263,24 +263,25 @@ async function generatePoe(type, finalPrompt, signal) {
|
||||
}
|
||||
|
||||
const isQuiet = type === 'quiet';
|
||||
const isImpersonate = type === 'impersonate';
|
||||
let reply = '';
|
||||
|
||||
if (max_context > POE_TOKEN_LENGTH && poe_settings.bot !== 'a2_100k') {
|
||||
console.debug('Prompt is too long, sending in chunks');
|
||||
const result = await sendChunkedMessage(finalPrompt, !isQuiet, signal)
|
||||
const result = await sendChunkedMessage(finalPrompt, !isQuiet, !isQuiet && !isImpersonate, signal)
|
||||
reply = result.reply;
|
||||
messages_to_purge = result.chunks + 1; // +1 for the reply
|
||||
}
|
||||
else {
|
||||
console.debug('Sending prompt in one message');
|
||||
reply = await sendMessage(finalPrompt, !isQuiet, !isQuiet, signal);
|
||||
reply = await sendMessage(finalPrompt, !isQuiet, !isQuiet && !isImpersonate, signal);
|
||||
messages_to_purge = 2; // prompt and the reply
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
async function sendChunkedMessage(finalPrompt, withStreaming, signal) {
|
||||
async function sendChunkedMessage(finalPrompt, withStreaming, withSuggestions, signal) {
|
||||
const fastReplyPrompt = '\n[Reply to this message with a full stop only]';
|
||||
const promptChunks = splitRecursive(finalPrompt, CHUNKED_PROMPT_LENGTH - fastReplyPrompt.length);
|
||||
console.debug(`Splitting prompt into ${promptChunks.length} chunks`, promptChunks);
|
||||
@@ -291,7 +292,7 @@ async function sendChunkedMessage(finalPrompt, withStreaming, signal) {
|
||||
console.debug(`Sending chunk ${i + 1}/${promptChunks.length}: ${promptChunk}`);
|
||||
if (i == promptChunks.length - 1) {
|
||||
// Extract reply of the last chunk
|
||||
reply = await sendMessage(promptChunk, withStreaming, true, signal);
|
||||
reply = await sendMessage(promptChunk, withStreaming, withSuggestions, signal);
|
||||
} else {
|
||||
// Add fast reply prompt to the chunk
|
||||
promptChunk += fastReplyPrompt;
|
||||
|
21
public/themes/Default (Dark) 1.7.1.json
Normal file
21
public/themes/Default (Dark) 1.7.1.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Default (Dark) 1.7.1",
|
||||
"blur_strength": 10,
|
||||
"main_text_color": "rgba(220, 220, 210, 1)",
|
||||
"italics_text_color": "rgba(145, 145, 145, 1)",
|
||||
"quote_text_color": "rgba(225, 138, 36, 1)",
|
||||
"blur_tint_color": "rgba(23, 23, 23, 1)",
|
||||
"user_mes_blur_tint_color": "rgba(0, 0, 0, 0.9)",
|
||||
"bot_mes_blur_tint_color": "rgba(0, 0, 0, 0.9)",
|
||||
"shadow_color": "rgba(0, 0, 0, 1)",
|
||||
"shadow_width": 2,
|
||||
"font_scale": 1,
|
||||
"fast_ui_mode": true,
|
||||
"waifuMode": false,
|
||||
"avatar_style": 0,
|
||||
"chat_display": 0,
|
||||
"noShadows": true,
|
||||
"sheld_width": 0,
|
||||
"timer_enabled": false,
|
||||
"hotswap_enabled": true
|
||||
}
|
21
public/themes/Ross v2.json
Normal file
21
public/themes/Ross v2.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Ross v2",
|
||||
"blur_strength": 10,
|
||||
"main_text_color": "rgba(230, 230, 220, 1)",
|
||||
"italics_text_color": "rgba(145, 145, 145, 1)",
|
||||
"quote_text_color": "rgba(73, 179, 255, 0.91)",
|
||||
"blur_tint_color": "rgba(0, 0, 0, 0.5)",
|
||||
"user_mes_blur_tint_color": "rgba(51, 51, 51, 0.2)",
|
||||
"bot_mes_blur_tint_color": "rgba(97, 97, 97, 0.43)",
|
||||
"shadow_color": "rgba(0, 0, 0, 0.5)",
|
||||
"shadow_width": 2,
|
||||
"font_scale": 0.95,
|
||||
"fast_ui_mode": false,
|
||||
"waifuMode": false,
|
||||
"avatar_style": 1,
|
||||
"chat_display": 1,
|
||||
"noShadows": false,
|
||||
"sheld_width": 1,
|
||||
"timer_enabled": true,
|
||||
"hotswap_enabled": true
|
||||
}
|
11
server.js
11
server.js
@@ -357,14 +357,17 @@ app.post("/generate", jsonParser, async function (request, response_generate = r
|
||||
request.socket.on('close', async function () {
|
||||
if (request.body.can_abort && !response_generate.finished) {
|
||||
try {
|
||||
console.log('Aborting Kobold generation...');
|
||||
// send abort signal to koboldcpp
|
||||
await fetch(`${api_server}/extra/abort`, {
|
||||
const abortResponse = await fetch(`${api_server}/extra/abort`, {
|
||||
method: 'POST',
|
||||
});
|
||||
} catch {
|
||||
if ('status' in error) {
|
||||
console.log('Status Code from Kobold:', error.status);
|
||||
|
||||
if (!abortResponse.ok) {
|
||||
console.log('Error sending abort request to Kobold:', abortResponse.status);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
controller.abort();
|
||||
|
@@ -24,6 +24,7 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
const _ = require('lodash');
|
||||
|
||||
const directory = __dirname;
|
||||
|
||||
@@ -281,6 +282,33 @@ async function request_with_retries(method, attempts = 10) {
|
||||
throw new Error(`Failed to download ${url} too many times.`);
|
||||
}
|
||||
|
||||
function findKey(obj, key, path = []) {
|
||||
if (obj && typeof obj === 'object') {
|
||||
if (key in obj) {
|
||||
return [...path, key];
|
||||
}
|
||||
for (const k in obj) {
|
||||
const result = findKey(obj[k], key, [...path, k]);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function logObjectStructure(obj, indent = 0, depth = Infinity) {
|
||||
const keys = Object.keys(obj);
|
||||
keys.forEach((key) => {
|
||||
console.log(`${' '.repeat(indent)}${key}`);
|
||||
if (typeof obj[key] === 'object' && obj[key] !== null && indent < depth) {
|
||||
logObjectStructure(obj[key], indent + 1, depth);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Client {
|
||||
gql_url = "https://poe.com/api/gql_POST";
|
||||
gql_recv_url = "https://poe.com/api/receive_POST";
|
||||
@@ -363,19 +391,52 @@ class Client {
|
||||
async get_next_data() {
|
||||
logger.info('Downloading next_data...');
|
||||
|
||||
//these keys are used as of June 29, 2023
|
||||
//if API changes in the future, just change these to find the new path
|
||||
const viewerKeyName = 'viewer'
|
||||
const botNameKeyName = 'chatOfBotDisplayName'
|
||||
const defaultBotKeyName = 'defaultBotNickname'
|
||||
|
||||
const r = await request_with_retries(() => this.session.get(this.home_url));
|
||||
const jsonRegex = /<script id="__NEXT_DATA__" type="application\/json">(.+?)<\/script>/;
|
||||
const jsonText = jsonRegex.exec(r.data)[1];
|
||||
const nextData = JSON.parse(jsonText);
|
||||
|
||||
const viewerPath = findKey(nextData, viewerKeyName);
|
||||
const botNamePath = findKey(nextData, botNameKeyName);
|
||||
const defaultBotPath = findKey(nextData, defaultBotKeyName);
|
||||
console.log(`DefaultBot found at: ${defaultBotPath.join('.')}`)
|
||||
|
||||
let viewer = null;
|
||||
if (viewerPath) {
|
||||
viewer = _.get(nextData, viewerPath.join('.'));
|
||||
}
|
||||
|
||||
//if the API changes, these reports will tell us how it changed
|
||||
if (viewerPath) {
|
||||
console.log(`'${viewerKeyName}' key: ${viewerPath.join('.')}`);
|
||||
} else {
|
||||
console.log(`ERROR: '${viewerKeyName}' key not found.`);
|
||||
//console.log(logObjectStructure(nextData, 0, 2));
|
||||
}
|
||||
if (botNamePath) {
|
||||
console.log(`'${botNameKeyName}' key: ${botNamePath.join('.')}`);
|
||||
} else {
|
||||
console.log(`ERROR: '${botNameKeyName}' key not found.`);
|
||||
//console.log(logObjectStructure(nextData, 0, 2));
|
||||
}
|
||||
|
||||
this.formkey = extractFormKey(r.data);
|
||||
this.viewer = nextData.props.pageProps.payload.viewer;
|
||||
this.viewer = viewer;
|
||||
|
||||
//old hard coded message no longer needed
|
||||
//this.viewer = nextData.props.pageProps.payload?.viewer || nextData.props.pageProps.data?.viewer;
|
||||
|
||||
return nextData;
|
||||
}
|
||||
|
||||
async get_bots() {
|
||||
const viewer = this.next_data.props.pageProps.payload.viewer;
|
||||
const viewer = this.viewer;
|
||||
if (!viewer.availableBotsConnection) {
|
||||
throw new Error('Invalid token.');
|
||||
}
|
||||
@@ -393,12 +454,12 @@ class Client {
|
||||
r = cached_bots[url];
|
||||
}
|
||||
else {
|
||||
logger.info(`Downloading ${url}`);
|
||||
logger.info(`Downloading ${bot.displayName}`);
|
||||
r = await request_with_retries(() => this.session.get(url), retries);
|
||||
cached_bots[url] = r;
|
||||
}
|
||||
|
||||
const chatData = r.data.pageProps.payload.chatOfBotDisplayName;
|
||||
const chatData = r.data.pageProps.payload?.chatOfBotDisplayName || r.data.pageProps.data?.chatOfBotDisplayName;
|
||||
bots[chatData.defaultBotObject.nickname] = chatData;
|
||||
resolve();
|
||||
|
||||
@@ -661,14 +722,14 @@ class Client {
|
||||
signal.throwIfAborted();
|
||||
}
|
||||
|
||||
if (timeout == 0) {
|
||||
if (timeout <= 0) {
|
||||
throw new Error("Response timed out.");
|
||||
}
|
||||
|
||||
const message = this.message_queues[humanMessageId].shift();
|
||||
if (!message) {
|
||||
timeout -= 1;
|
||||
await delay(1000);
|
||||
timeout -= 0.1;
|
||||
await delay(100);
|
||||
continue;
|
||||
//throw new Error("Queue is empty");
|
||||
}
|
||||
|
16
start.sh
16
start.sh
@@ -3,19 +3,19 @@
|
||||
if ! command -v npm &> /dev/null
|
||||
then
|
||||
read -p "npm is not installed. Do you want to install nodejs and npm? (y/n)" choice
|
||||
case "$choice" in
|
||||
y|Y )
|
||||
case "$choice" in
|
||||
y|Y )
|
||||
echo "Installing nvm..."
|
||||
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
|
||||
source ~/.bashrc
|
||||
nvm install lts
|
||||
nvm use lts;;
|
||||
n|N )
|
||||
nvm install --lts
|
||||
nvm use --lts;;
|
||||
n|N )
|
||||
echo "Nodejs and npm will not be installed."
|
||||
exit;;
|
||||
* )
|
||||
* )
|
||||
echo "Invalid option. Nodejs and npm will not be installed."
|
||||
exit;;
|
||||
esac
|
||||
@@ -28,7 +28,7 @@ if [ ! -z "$REPL_ID" ]; then
|
||||
fi
|
||||
|
||||
echo "Installing Node Modules..."
|
||||
npm i
|
||||
npm i --no-audit
|
||||
|
||||
echo "Entering SillyTavern..."
|
||||
node "$(dirname "$0")/server.js"
|
||||
node "$(dirname "$0")/server.js"
|
||||
|
Reference in New Issue
Block a user