Merge branch 'staging' into tags-as-folders-enhancements

This commit is contained in:
Wolfsblvt 2024-03-07 16:09:57 +01:00
commit 7b49290fec
10 changed files with 715 additions and 1085 deletions

View File

@ -12,11 +12,14 @@ ENTRYPOINT [ "tini", "--" ]
# Create app directory # Create app directory
WORKDIR ${APP_HOME} WORKDIR ${APP_HOME}
# Set NODE_ENV to production
ENV NODE_ENV=production
# Install app dependencies # Install app dependencies
COPY package*.json post-install.js ./ COPY package*.json post-install.js ./
RUN \ RUN \
echo "*** Install npm packages ***" && \ echo "*** Install npm packages ***" && \
npm install && npm cache clean --force npm i --no-audit --no-fund --quiet --omit=dev && npm cache clean --force
# Bundle app source # Bundle app source
COPY . ./ COPY . ./

View File

@ -1,5 +1,6 @@
pushd %~dp0 pushd %~dp0
call npm install --no-audit set NODE_ENV=production
call npm install --no-audit --no-fund --quiet --omit=dev
node server.js %* node server.js %*
pause pause
popd popd

View File

@ -11,7 +11,8 @@ if %errorlevel% neq 0 (
echo There were errors while updating. Please download the latest version manually. echo There were errors while updating. Please download the latest version manually.
) )
) )
call npm install set NODE_ENV=production
call npm install --no-audit --no-fund --quiet --omit=dev
node server.js %* node server.js %*
pause pause
popd popd

1654
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -47,6 +47,9 @@
}, },
"axios": { "axios": {
"follow-redirects": "^1.15.4" "follow-redirects": "^1.15.4"
},
"@zeldafan0225/ai_horde": {
"esbuild": "npm:dry-uninstall"
} }
}, },
"name": "sillytavern", "name": "sillytavern",

View File

@ -7204,6 +7204,11 @@ async function createOrEditCharacter(e) {
formData.set('fav', fav_ch_checked); formData.set('fav', fav_ch_checked);
if ($('#form_create').attr('actiontype') == 'createcharacter') { if ($('#form_create').attr('actiontype') == 'createcharacter') {
if ($('#character_name_pole').val().length > 0) { if ($('#character_name_pole').val().length > 0) {
if (is_group_generating || is_send_press) {
toastr.error('Cannot create characters while generating. Stop the request and try again.', 'Creation aborted');
throw new Error('Cannot import character while generating');
}
//if the character name text area isn't empty (only posible when creating a new character) //if the character name text area isn't empty (only posible when creating a new character)
let url = '/api/characters/create'; let url = '/api/characters/create';
@ -7956,6 +7961,11 @@ export async function processDroppedFiles(files, preserveFileNames = false) {
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async function importCharacter(file, preserveFileName = false) { async function importCharacter(file, preserveFileName = false) {
if (is_group_generating || is_send_press) {
toastr.error('Cannot import characters while generating. Stop the request and try again.', 'Import aborted');
throw new Error('Cannot import character while generating');
}
const ext = file.name.match(/\.(\w+)$/); const ext = file.name.match(/\.(\w+)$/);
if (!ext || !(['json', 'png', 'yaml', 'yml'].includes(ext[1].toLowerCase()))) { if (!ext || !(['json', 'png', 'yaml', 'yml'].includes(ext[1].toLowerCase()))) {
return; return;

View File

@ -76,48 +76,93 @@ class SlashCommandParser {
this.helpStrings[command] = stringBuilder; this.helpStrings[command] = stringBuilder;
} }
/**
* Parses a slash command to extract the command name, the (named) arguments and the remaining text
* @param {string} text - Slash command text
* @returns {{command: string, args: object, value: string}} - The parsed command, its arguments and the remaining text
*/
parse(text) { parse(text) {
// Parses a command even when spaces are present in arguments
// /buttons labels=["OK","I do not accept"] some text
// /fuzzy list=[ "red pink" , "yellow" ] threshold=" 0.6 " he yelled when the color was reddish and not pink | /echo
const excludedFromRegex = ['sendas']; const excludedFromRegex = ['sendas'];
const firstSpace = text.indexOf(' '); let command = '';
const command = firstSpace !== -1 ? text.substring(1, firstSpace) : text.substring(1);
let args = firstSpace !== -1 ? text.substring(firstSpace + 1) : '';
const argObj = {}; const argObj = {};
let unnamedArg; let unnamedArg = '';
if (args.length > 0) { // extract the command " /fuzzy " => "fuzzy"
let match; text = text.trim();
let remainingText = '';
// Match unnamed argument const commandArgPattern = /^\/([^\s]+)\s*(.*)$/s;
const unnamedArgPattern = /(?:\w+=(?:"(?:\\.|[^"\\])*"|\S+)\s*)*(.*)/s; let match = commandArgPattern.exec(text);
match = unnamedArgPattern.exec(args); if (match !== null && match[1].length > 0) {
if (match !== null && match[1].length > 0) { command = match[1];
args = args.slice(0, -match[1].length); remainingText = match[2];
unnamedArg = match[1].trim(); console.debug('command:' + command);
}
// Match named arguments
const namedArgPattern = /(\w+)=("(?:\\.|[^"\\])*"|\S+)/g;
while ((match = namedArgPattern.exec(args)) !== null) {
const key = match[1];
const value = match[2];
// Remove the quotes around the value, if any
argObj[key] = value.replace(/(^")|("$)/g, '');
}
// Excluded commands format in their own function
if (!excludedFromRegex.includes(command)) {
unnamedArg = getRegexedString(
unnamedArg,
regex_placement.SLASH_COMMAND,
);
}
} }
// parse the rest of the string to extract named arguments, the remainder is the "unnamedArg" which is usually text, like the prompt to send
while (remainingText.length > 0) {
// does the remaining text is like nameArg=[value] or nameArg=[value,value] or nameArg=[ value , value , value]
// where value can be a string like " this is some text " , note previously it was not possible to have have spaces
// where value can be a scalar like AScalar
// where value can be a number like +9 -1005.44
// where value can be a macro like {{getvar::name}}
const namedArrayArgPattern = /^(\w+)=\[\s*(((?<quote>["'])[^"]*(\k<quote>)|{{[^}]*}}|[+-]?\d*\.?\d+|\w*)\s*,?\s*)+\]/s;
match = namedArrayArgPattern.exec(remainingText);
if (match !== null && match[0].length > 0) {
//console.log(`matching: ${match[0]}`);
const posFirstEqual = match[0].indexOf('=');
const key = match[0].substring(0, posFirstEqual).trim();
const value = match[0].substring(posFirstEqual + 1).trim();
// Remove the quotes around the value, if any
argObj[key] = value.replace(/(^")|("$)/g, '');
remainingText = remainingText.slice(match[0].length + 1).trim();
continue;
}
// does the remaining text is like nameArg=value
// where value can be a string like " this is some text " , note previously it was not possible to have have spaces
// where value can be a scalar like AScalar
// where value can be a number like +9 -1005.44
// where value can be a macro like {{getvar::name}}
const namedScalarArgPattern = /^(\w+)=(((?<quote>["'])[^"]*(\k<quote>)|{{[^}]*}}|[+-]?\d*\.?\d+|\w*))/s;
match = namedScalarArgPattern.exec(remainingText);
if (match !== null && match[0].length > 0) {
//console.log(`matching: ${match[0]}`);
const posFirstEqual = match[0].indexOf('=');
const key = match[0].substring(0, posFirstEqual).trim();
const value = match[0].substring(posFirstEqual + 1).trim();
// Remove the quotes around the value, if any
argObj[key] = value.replace(/(^")|("$)/g, '');
remainingText = remainingText.slice(match[0].length + 1).trim();
continue;
}
// the remainder that matches no named argument is the "unamedArg" previously mentioned
unnamedArg = remainingText.trim();
remainingText = '';
}
// Excluded commands format in their own function
if (!excludedFromRegex.includes(command)) {
console.debug(`parse: !excludedFromRegex.includes(${command}`);
console.debug(` parse: unnamedArg before: ${unnamedArg}`);
unnamedArg = getRegexedString(
unnamedArg,
regex_placement.SLASH_COMMAND,
);
console.debug(` parse: unnamedArg after: ${unnamedArg}`);
}
// your weird complex command is now transformed into a juicy tiny text or something useful :)
if (this.commands[command]) { if (this.commands[command]) {
return { command: this.commands[command], args: argObj, value: unnamedArg }; return { command: this.commands[command], args: argObj, value: unnamedArg };
} }
return false; return null;
} }
getHelpString() { getHelpString() {

View File

@ -93,8 +93,8 @@ const cliArguments = yargs(hideBin(process.argv))
}).parseSync(); }).parseSync();
// change all relative paths // change all relative paths
const serverDirectory = process['pkg'] ? path.dirname(process.execPath) : __dirname; console.log(`Running in ${process.env.NODE_ENV} environment`);
console.log(process['pkg'] ? 'Running from binary' : 'Running from source'); const serverDirectory = __dirname;
process.chdir(serverDirectory); process.chdir(serverDirectory);
const app = express(); const app = express();

View File

@ -151,7 +151,11 @@ function convertClaudeMessages(messages, prefillString, useSysPrompt, humanMsgFi
// Take care of name properties since claude messages don't support them // Take care of name properties since claude messages don't support them
mergedMessages.forEach((message) => { mergedMessages.forEach((message) => {
if (message.name) { if (message.name) {
message.content = `${message.name}: ${message.content}`; if (Array.isArray(message.content)) {
message.content[0].text = `${message.name}: ${message.content[0].text}`;
} else {
message.content = `${message.name}: ${message.content}`;
}
delete message.name; delete message.name;
} }
}); });

View File

@ -28,7 +28,8 @@ if [ ! -z "$REPL_ID" ]; then
fi fi
echo "Installing Node Modules..." echo "Installing Node Modules..."
npm i --no-audit export NODE_ENV=production
npm i --no-audit --no-fund --quiet --omit=dev
echo "Entering SillyTavern..." echo "Entering SillyTavern..."
node "$(dirname "$0")/server.js" "$@" node "$(dirname "$0")/server.js" "$@"