Merge pull request #1885 from parsedone/patch-1

Fixes [BUG] STscript /fuzzy returning wrong answer
This commit is contained in:
Cohee 2024-03-03 16:07:12 +02:00 committed by GitHub
commit 314c52fa5f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 42 additions and 11 deletions

View File

@ -173,8 +173,7 @@ parser.addCommand('gen', generateCallback, [], '<span class="monospace">(lock=on
parser.addCommand('genraw', generateRawCallback, [], '<span class="monospace">(lock=on/off [prompt])</span> generates text using the provided prompt and passes it to the next command through the pipe, optionally locking user input while generating. Does not include chat history or character card. Use instruct=off to skip instruct formatting, e.g. <tt>/genraw instruct=off Why is the sky blue?</tt>. Use stop=... with a JSON-serialized array to add one-time custom stop strings, e.g. <tt>/genraw stop=["\\n"] Say hi</tt>', true, true); parser.addCommand('genraw', generateRawCallback, [], '<span class="monospace">(lock=on/off [prompt])</span> generates text using the provided prompt and passes it to the next command through the pipe, optionally locking user input while generating. Does not include chat history or character card. Use instruct=off to skip instruct formatting, e.g. <tt>/genraw instruct=off Why is the sky blue?</tt>. Use stop=... with a JSON-serialized array to add one-time custom stop strings, e.g. <tt>/genraw stop=["\\n"] Say hi</tt>', true, true);
parser.addCommand('addswipe', addSwipeCallback, ['swipeadd'], '<span class="monospace">(text)</span> adds a swipe to the last chat message.', true, true); parser.addCommand('addswipe', addSwipeCallback, ['swipeadd'], '<span class="monospace">(text)</span> adds a swipe to the last chat message.', true, true);
parser.addCommand('abort', abortCallback, [], ' aborts the slash command batch execution', true, true); parser.addCommand('abort', abortCallback, [], ' aborts the slash command batch execution', true, true);
parser.addCommand('fuzzy', fuzzyCallback, [], 'list=["a","b","c"] (search value) performs a fuzzy match of the provided search using the provided list of value and passes the closest match to the next command through the pipe.', true, true); parser.addCommand('fuzzy', fuzzyCallback, [], 'list=["a","b","c"] threshold=0.4 (text to search) performs a fuzzy match of each items of list within the text to search. If any item matches then its name is returned. If no item list matches the text to search then no value is returned. The optional threshold (default is 0.4) allows some control over the matching. A low value (min 0.0) means the match is very strict. At 1.0 (max) the match is very loose and probably matches anything. The returned value passes to the next command through the pipe.', true, true); parser.addCommand('pass', (_, arg) => arg, ['return'], '<span class="monospace">(text)</span> passes the text to the next command through the pipe.', true, true);
parser.addCommand('pass', (_, arg) => arg, ['return'], '<span class="monospace">(text)</span> passes the text to the next command through the pipe.', true, true);
parser.addCommand('delay', delayCallback, ['wait', 'sleep'], '<span class="monospace">(milliseconds)</span> delays the next command in the pipe by the specified number of milliseconds.', true, true); parser.addCommand('delay', delayCallback, ['wait', 'sleep'], '<span class="monospace">(milliseconds)</span> delays the next command in the pipe by the specified number of milliseconds.', true, true);
parser.addCommand('input', inputCallback, ['prompt'], '<span class="monospace">(default="string" large=on/off wide=on/off okButton="string" rows=number [text])</span> Shows a popup with the provided text and an input field. The default argument is the default value of the input field, and the text argument is the text to display.', true, true); parser.addCommand('input', inputCallback, ['prompt'], '<span class="monospace">(default="string" large=on/off wide=on/off okButton="string" rows=number [text])</span> Shows a popup with the provided text and an input field. The default argument is the default value of the input field, and the text argument is the text to display.', true, true);
parser.addCommand('run', runCallback, ['call', 'exec'], '<span class="monospace">[key1=value key2=value ...] ([qrSet.]qrLabel)</span> runs a Quick Reply with the specified name from a currently active preset or from another preset, named arguments can be referenced in a QR with {{arg::key}}.', true, true); parser.addCommand('run', runCallback, ['call', 'exec'], '<span class="monospace">[key1=value key2=value ...] ([qrSet.]qrLabel)</span> runs a Quick Reply with the specified name from a currently active preset or from another preset, named arguments can be referenced in a QR with {{arg::key}}.', true, true);
@ -502,8 +501,17 @@ async function inputCallback(args, prompt) {
return result || ''; return result || '';
} }
function fuzzyCallback(args, value) { /**
if (!value) { * Each item in "args.list" is searched within "search_item" using fuzzy search. If any matches it returns the matched "item".
* @param {FuzzyCommandArgs} args - arguments containing "list" (JSON array) and optionaly "threshold" (float between 0.0 and 1.0)
* @param {string} searchInValue - the string where items of list are searched
* @returns {string} - the matched item from the list
* @typedef {{list: string, threshold: string}} FuzzyCommandArgs - arguments for /fuzzy command
* @example /fuzzy list=["down","left","up","right"] "he looks up" | /echo // should return "up"
* @link https://www.fusejs.io/
*/
function fuzzyCallback(args, searchInValue) {
if (!searchInValue) {
console.warn('WARN: No argument provided for /fuzzy command'); console.warn('WARN: No argument provided for /fuzzy command');
return ''; return '';
} }
@ -520,14 +528,37 @@ function fuzzyCallback(args, value) {
return ''; return '';
} }
const fuse = new Fuse(list, { const params = {
includeScore: true, includeScore: true,
findAllMatches: true, findAllMatches: true,
ignoreLocation: true, ignoreLocation: true,
threshold: 0.7, threshold: 0.4,
}); };
const result = fuse.search(value); // threshold determines how strict is the match, low threshold value is very strict, at 1 (nearly?) everything matches
return result[0]?.item; if ('threshold' in args) {
params.threshold = parseFloat(resolveVariable(args.threshold));
if (isNaN(params.threshold)) {
console.warn('WARN: \'threshold\' argument must be a float between 0.0 and 1.0 for /fuzzy command');
return '';
}
if (params.threshold < 0) {
params.threshold = 0;
}
if (params.threshold > 1) {
params.threshold = 1;
}
}
const fuse = new Fuse([searchInValue], params);
// each item in the "list" is searched within "search_item", if any matches it returns the matched "item"
for (const searchItem of list) {
const result = fuse.search(searchItem);
if (result.length > 0) {
console.info('fuzzyCallback Matched: ' + searchItem);
return searchItem;
}
}
return '';
} catch { } catch {
console.warn('WARN: Invalid list argument provided for /fuzzy command'); console.warn('WARN: Invalid list argument provided for /fuzzy command');
return ''; return '';
@ -1584,7 +1615,7 @@ async function executeSlashCommands(text, unescape = false) {
?.replace(/\\\|/g, '|') ?.replace(/\\\|/g, '|')
?.replace(/\\\{/g, '{') ?.replace(/\\\{/g, '{')
?.replace(/\\\}/g, '}') ?.replace(/\\\}/g, '}')
; ;
} }
for (const [key, value] of Object.entries(result.args)) { for (const [key, value] of Object.entries(result.args)) {
@ -1593,7 +1624,7 @@ async function executeSlashCommands(text, unescape = false) {
.replace(/\\\|/g, '|') .replace(/\\\|/g, '|')
.replace(/\\\{/g, '{') .replace(/\\\{/g, '{')
.replace(/\\\}/g, '}') .replace(/\\\}/g, '}')
; ;
} }
} }