mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-07 15:48:46 +01:00
Merge pull request #1011 from bdashore3/generate-array
Generate: Change prompt building mechanisms
This commit is contained in:
commit
11ba93aa10
@ -45,6 +45,7 @@
|
|||||||
<script src="lib/pagination.js"></script>
|
<script src="lib/pagination.js"></script>
|
||||||
<script src="lib/toolcool-color-picker.js"></script>
|
<script src="lib/toolcool-color-picker.js"></script>
|
||||||
<script src="lib/svg-inject.js"></script>
|
<script src="lib/svg-inject.js"></script>
|
||||||
|
<script type="module" src="lib/structured-clone/monkey-patch.js"></script>
|
||||||
<script type="module" src="lib/swiped-events.js"></script>
|
<script type="module" src="lib/swiped-events.js"></script>
|
||||||
<script type="module" src="lib/eventemitter.js"></script>
|
<script type="module" src="lib/eventemitter.js"></script>
|
||||||
<script type="module" src="scripts/power-user.js"></script>
|
<script type="module" src="scripts/power-user.js"></script>
|
||||||
|
15
public/lib/structured-clone/LICENSE
Normal file
15
public/lib/structured-clone/LICENSE
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (c) 2021, Andrea Giammarchi, @WebReflection
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||||
|
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
PERFORMANCE OF THIS SOFTWARE.
|
79
public/lib/structured-clone/deserialize.js
Normal file
79
public/lib/structured-clone/deserialize.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import {
|
||||||
|
VOID, PRIMITIVE,
|
||||||
|
ARRAY, OBJECT,
|
||||||
|
DATE, REGEXP, MAP, SET,
|
||||||
|
ERROR, BIGINT
|
||||||
|
} from './types.js';
|
||||||
|
|
||||||
|
const env = typeof self === 'object' ? self : globalThis;
|
||||||
|
|
||||||
|
const deserializer = ($, _) => {
|
||||||
|
const as = (out, index) => {
|
||||||
|
$.set(index, out);
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
|
const unpair = index => {
|
||||||
|
if ($.has(index))
|
||||||
|
return $.get(index);
|
||||||
|
|
||||||
|
const [type, value] = _[index];
|
||||||
|
switch (type) {
|
||||||
|
case PRIMITIVE:
|
||||||
|
case VOID:
|
||||||
|
return as(value, index);
|
||||||
|
case ARRAY: {
|
||||||
|
const arr = as([], index);
|
||||||
|
for (const index of value)
|
||||||
|
arr.push(unpair(index));
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
case OBJECT: {
|
||||||
|
const object = as({}, index);
|
||||||
|
for (const [key, index] of value)
|
||||||
|
object[unpair(key)] = unpair(index);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
case DATE:
|
||||||
|
return as(new Date(value), index);
|
||||||
|
case REGEXP: {
|
||||||
|
const {source, flags} = value;
|
||||||
|
return as(new RegExp(source, flags), index);
|
||||||
|
}
|
||||||
|
case MAP: {
|
||||||
|
const map = as(new Map, index);
|
||||||
|
for (const [key, index] of value)
|
||||||
|
map.set(unpair(key), unpair(index));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
case SET: {
|
||||||
|
const set = as(new Set, index);
|
||||||
|
for (const index of value)
|
||||||
|
set.add(unpair(index));
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
case ERROR: {
|
||||||
|
const {name, message} = value;
|
||||||
|
return as(new env[name](message), index);
|
||||||
|
}
|
||||||
|
case BIGINT:
|
||||||
|
return as(BigInt(value), index);
|
||||||
|
case 'BigInt':
|
||||||
|
return as(Object(BigInt(value)), index);
|
||||||
|
}
|
||||||
|
return as(new env[type](value), index);
|
||||||
|
};
|
||||||
|
|
||||||
|
return unpair;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Array<string,any>} Record a type representation
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a deserialized value from a serialized array of Records.
|
||||||
|
* @param {Record[]} serialized a previously serialized value.
|
||||||
|
* @returns {any}
|
||||||
|
*/
|
||||||
|
export const deserialize = serialized => deserializer(new Map, serialized)(0);
|
25
public/lib/structured-clone/index.js
Normal file
25
public/lib/structured-clone/index.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import {deserialize} from './deserialize.js';
|
||||||
|
import {serialize} from './serialize.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Array<string,any>} Record a type representation
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of serialized Records.
|
||||||
|
* @param {any} any a serializable value.
|
||||||
|
* @param {{transfer?: any[], json?: boolean, lossy?: boolean}?} options an object with
|
||||||
|
* a transfer option (ignored when polyfilled) and/or non standard fields that
|
||||||
|
* fallback to the polyfill if present.
|
||||||
|
* @returns {Record[]}
|
||||||
|
*/
|
||||||
|
export default typeof structuredClone === "function" ?
|
||||||
|
/* c8 ignore start */
|
||||||
|
(any, options) => (
|
||||||
|
options && ('json' in options || 'lossy' in options) ?
|
||||||
|
deserialize(serialize(any, options)) : structuredClone(any)
|
||||||
|
) :
|
||||||
|
(any, options) => deserialize(serialize(any, options));
|
||||||
|
/* c8 ignore stop */
|
||||||
|
|
||||||
|
export {deserialize, serialize};
|
21
public/lib/structured-clone/json.js
Normal file
21
public/lib/structured-clone/json.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*! (c) Andrea Giammarchi - ISC */
|
||||||
|
|
||||||
|
import {deserialize} from './deserialize.js';
|
||||||
|
import {serialize} from './serialize.js';
|
||||||
|
|
||||||
|
const {parse: $parse, stringify: $stringify} = JSON;
|
||||||
|
const options = {json: true, lossy: true};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revive a previously stringified structured clone.
|
||||||
|
* @param {string} str previously stringified data as string.
|
||||||
|
* @returns {any} whatever was previously stringified as clone.
|
||||||
|
*/
|
||||||
|
export const parse = str => deserialize($parse(str));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent a structured clone value as string.
|
||||||
|
* @param {any} any some clone-able value to stringify.
|
||||||
|
* @returns {string} the value stringified.
|
||||||
|
*/
|
||||||
|
export const stringify = any => $stringify(serialize(any, options));
|
6
public/lib/structured-clone/monkey-patch.js
Normal file
6
public/lib/structured-clone/monkey-patch.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import structuredClone from './index.js';
|
||||||
|
|
||||||
|
if (!("structuredClone" in globalThis)) {
|
||||||
|
console.debug("Monkey-patching structuredClone");
|
||||||
|
globalThis.structuredClone = structuredClone;
|
||||||
|
}
|
161
public/lib/structured-clone/serialize.js
Normal file
161
public/lib/structured-clone/serialize.js
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import {
|
||||||
|
VOID, PRIMITIVE,
|
||||||
|
ARRAY, OBJECT,
|
||||||
|
DATE, REGEXP, MAP, SET,
|
||||||
|
ERROR, BIGINT
|
||||||
|
} from './types.js';
|
||||||
|
|
||||||
|
const EMPTY = '';
|
||||||
|
|
||||||
|
const {toString} = {};
|
||||||
|
const {keys} = Object;
|
||||||
|
|
||||||
|
const typeOf = value => {
|
||||||
|
const type = typeof value;
|
||||||
|
if (type !== 'object' || !value)
|
||||||
|
return [PRIMITIVE, type];
|
||||||
|
|
||||||
|
const asString = toString.call(value).slice(8, -1);
|
||||||
|
switch (asString) {
|
||||||
|
case 'Array':
|
||||||
|
return [ARRAY, EMPTY];
|
||||||
|
case 'Object':
|
||||||
|
return [OBJECT, EMPTY];
|
||||||
|
case 'Date':
|
||||||
|
return [DATE, EMPTY];
|
||||||
|
case 'RegExp':
|
||||||
|
return [REGEXP, EMPTY];
|
||||||
|
case 'Map':
|
||||||
|
return [MAP, EMPTY];
|
||||||
|
case 'Set':
|
||||||
|
return [SET, EMPTY];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asString.includes('Array'))
|
||||||
|
return [ARRAY, asString];
|
||||||
|
|
||||||
|
if (asString.includes('Error'))
|
||||||
|
return [ERROR, asString];
|
||||||
|
|
||||||
|
return [OBJECT, asString];
|
||||||
|
};
|
||||||
|
|
||||||
|
const shouldSkip = ([TYPE, type]) => (
|
||||||
|
TYPE === PRIMITIVE &&
|
||||||
|
(type === 'function' || type === 'symbol')
|
||||||
|
);
|
||||||
|
|
||||||
|
const serializer = (strict, json, $, _) => {
|
||||||
|
|
||||||
|
const as = (out, value) => {
|
||||||
|
const index = _.push(out) - 1;
|
||||||
|
$.set(value, index);
|
||||||
|
return index;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pair = value => {
|
||||||
|
if ($.has(value))
|
||||||
|
return $.get(value);
|
||||||
|
|
||||||
|
let [TYPE, type] = typeOf(value);
|
||||||
|
switch (TYPE) {
|
||||||
|
case PRIMITIVE: {
|
||||||
|
let entry = value;
|
||||||
|
switch (type) {
|
||||||
|
case 'bigint':
|
||||||
|
TYPE = BIGINT;
|
||||||
|
entry = value.toString();
|
||||||
|
break;
|
||||||
|
case 'function':
|
||||||
|
case 'symbol':
|
||||||
|
if (strict)
|
||||||
|
throw new TypeError('unable to serialize ' + type);
|
||||||
|
entry = null;
|
||||||
|
break;
|
||||||
|
case 'undefined':
|
||||||
|
return as([VOID], value);
|
||||||
|
}
|
||||||
|
return as([TYPE, entry], value);
|
||||||
|
}
|
||||||
|
case ARRAY: {
|
||||||
|
if (type)
|
||||||
|
return as([type, [...value]], value);
|
||||||
|
|
||||||
|
const arr = [];
|
||||||
|
const index = as([TYPE, arr], value);
|
||||||
|
for (const entry of value)
|
||||||
|
arr.push(pair(entry));
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
case OBJECT: {
|
||||||
|
if (type) {
|
||||||
|
switch (type) {
|
||||||
|
case 'BigInt':
|
||||||
|
return as([type, value.toString()], value);
|
||||||
|
case 'Boolean':
|
||||||
|
case 'Number':
|
||||||
|
case 'String':
|
||||||
|
return as([type, value.valueOf()], value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json && ('toJSON' in value))
|
||||||
|
return pair(value.toJSON());
|
||||||
|
|
||||||
|
const entries = [];
|
||||||
|
const index = as([TYPE, entries], value);
|
||||||
|
for (const key of keys(value)) {
|
||||||
|
if (strict || !shouldSkip(typeOf(value[key])))
|
||||||
|
entries.push([pair(key), pair(value[key])]);
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
case DATE:
|
||||||
|
return as([TYPE, value.toISOString()], value);
|
||||||
|
case REGEXP: {
|
||||||
|
const {source, flags} = value;
|
||||||
|
return as([TYPE, {source, flags}], value);
|
||||||
|
}
|
||||||
|
case MAP: {
|
||||||
|
const entries = [];
|
||||||
|
const index = as([TYPE, entries], value);
|
||||||
|
for (const [key, entry] of value) {
|
||||||
|
if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry))))
|
||||||
|
entries.push([pair(key), pair(entry)]);
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
case SET: {
|
||||||
|
const entries = [];
|
||||||
|
const index = as([TYPE, entries], value);
|
||||||
|
for (const entry of value) {
|
||||||
|
if (strict || !shouldSkip(typeOf(entry)))
|
||||||
|
entries.push(pair(entry));
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const {message} = value;
|
||||||
|
return as([TYPE, {name: type, message}], value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return pair;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Array<string,any>} Record a type representation
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of serialized Records.
|
||||||
|
* @param {any} value a serializable value.
|
||||||
|
* @param {{json?: boolean, lossy?: boolean}?} options an object with a `lossy` or `json` property that,
|
||||||
|
* if `true`, will not throw errors on incompatible types, and behave more
|
||||||
|
* like JSON stringify would behave. Symbol and Function will be discarded.
|
||||||
|
* @returns {Record[]}
|
||||||
|
*/
|
||||||
|
export const serialize = (value, {json, lossy} = {}) => {
|
||||||
|
const _ = [];
|
||||||
|
return serializer(!(json || lossy), !!json, new Map, _)(value), _;
|
||||||
|
};
|
11
public/lib/structured-clone/types.js
Normal file
11
public/lib/structured-clone/types.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export const VOID = -1;
|
||||||
|
export const PRIMITIVE = 0;
|
||||||
|
export const ARRAY = 1;
|
||||||
|
export const OBJECT = 2;
|
||||||
|
export const DATE = 3;
|
||||||
|
export const REGEXP = 4;
|
||||||
|
export const MAP = 5;
|
||||||
|
export const SET = 6;
|
||||||
|
export const ERROR = 7;
|
||||||
|
export const BIGINT = 8;
|
||||||
|
// export const SYMBOL = 9;
|
132
public/script.js
132
public/script.js
@ -157,7 +157,7 @@ import {
|
|||||||
} from "./scripts/secrets.js";
|
} from "./scripts/secrets.js";
|
||||||
import { EventEmitter } from './lib/eventemitter.js';
|
import { EventEmitter } from './lib/eventemitter.js';
|
||||||
import { markdownExclusionExt } from "./scripts/showdown-exclusion.js";
|
import { markdownExclusionExt } from "./scripts/showdown-exclusion.js";
|
||||||
import { NOTE_MODULE_NAME, metadata_keys, setFloatingPrompt, shouldWIAddPrompt } from "./scripts/authors-note.js";
|
import { NOTE_MODULE_NAME, initAuthorsNote, metadata_keys, setFloatingPrompt, shouldWIAddPrompt } from "./scripts/authors-note.js";
|
||||||
import { getDeviceInfo } from "./scripts/RossAscends-mods.js";
|
import { getDeviceInfo } from "./scripts/RossAscends-mods.js";
|
||||||
import { registerPromptManagerMigration } from "./scripts/PromptManager.js";
|
import { registerPromptManagerMigration } from "./scripts/PromptManager.js";
|
||||||
import { getRegexedString, regex_placement } from "./scripts/extensions/regex/engine.js";
|
import { getRegexedString, regex_placement } from "./scripts/extensions/regex/engine.js";
|
||||||
@ -2613,7 +2613,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
console.debug('generating prompt');
|
console.debug('generating prompt');
|
||||||
chatString = "";
|
chatString = "";
|
||||||
arrMes = arrMes.reverse();
|
arrMes = arrMes.reverse();
|
||||||
arrMes.forEach(function (item, i, arr) {//For added anchors and others
|
arrMes.forEach(function (item, i, arr) {// For added anchors and others
|
||||||
// OAI doesn't need all of this
|
// OAI doesn't need all of this
|
||||||
if (main_api === 'openai') {
|
if (main_api === 'openai') {
|
||||||
return;
|
return;
|
||||||
@ -2629,25 +2629,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i === 0) {
|
mesSend[mesSend.length] = { message: item, extensionPrompts: [] };
|
||||||
// Process those that couldn't get that far
|
|
||||||
for (let upperDepth = 100; upperDepth >= arrMes.length; upperDepth--) {
|
|
||||||
const upperAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, upperDepth);
|
|
||||||
if (upperAnchor && upperAnchor.length) {
|
|
||||||
item = upperAnchor + item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const anchorDepth = Math.abs(i - arrMes.length + 1);
|
|
||||||
// NOTE: Depth injected here!
|
|
||||||
const extensionAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, anchorDepth);
|
|
||||||
|
|
||||||
if (anchorDepth > 0 && extensionAnchor && extensionAnchor.length) {
|
|
||||||
item += extensionAnchor;
|
|
||||||
}
|
|
||||||
|
|
||||||
mesSend[mesSend.length] = item;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2662,7 +2644,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
mesExmString = pinExmString ?? mesExamplesArray.slice(0, count_exm_add).join('');
|
mesExmString = pinExmString ?? mesExamplesArray.slice(0, count_exm_add).join('');
|
||||||
|
|
||||||
if (mesSend.length) {
|
if (mesSend.length) {
|
||||||
mesSend[mesSend.length - 1] = modifyLastPromptLine(mesSend[mesSend.length - 1]);
|
mesSend[mesSend.length - 1].message = modifyLastPromptLine(mesSend[mesSend.length - 1].message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2761,6 +2743,10 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
|
|
||||||
// Fetches the combined prompt for both negative and positive prompts
|
// Fetches the combined prompt for both negative and positive prompts
|
||||||
const cfgGuidanceScale = getGuidanceScale();
|
const cfgGuidanceScale = getGuidanceScale();
|
||||||
|
|
||||||
|
// For prompt bit itemization
|
||||||
|
let mesSendString = '';
|
||||||
|
|
||||||
function getCombinedPrompt(isNegative) {
|
function getCombinedPrompt(isNegative) {
|
||||||
// Only return if the guidance scale doesn't exist or the value is 1
|
// Only return if the guidance scale doesn't exist or the value is 1
|
||||||
// Also don't return if constructing the neutral prompt
|
// Also don't return if constructing the neutral prompt
|
||||||
@ -2768,7 +2754,50 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let finalMesSend = [...mesSend];
|
// OAI has its own prompt manager. No need to do anything here
|
||||||
|
if (main_api === 'openai') {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deep clone
|
||||||
|
let finalMesSend = structuredClone(mesSend);
|
||||||
|
|
||||||
|
// TODO: Rewrite getExtensionPrompt to not require multiple for loops
|
||||||
|
// Set all extension prompts where insertion depth > mesSend length
|
||||||
|
if (finalMesSend.length) {
|
||||||
|
for (let upperDepth = 100; upperDepth >= finalMesSend.length; upperDepth--) {
|
||||||
|
const upperAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, upperDepth);
|
||||||
|
if (upperAnchor && upperAnchor.length) {
|
||||||
|
finalMesSend[0].extensionPrompts.push(upperAnchor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finalMesSend.forEach((mesItem, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const anchorDepth = Math.abs(index - finalMesSend.length + 1);
|
||||||
|
// NOTE: Depth injected here!
|
||||||
|
const extensionAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, anchorDepth);
|
||||||
|
|
||||||
|
if (anchorDepth > 0 && extensionAnchor && extensionAnchor.length) {
|
||||||
|
mesItem.extensionPrompts.push(extensionAnchor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Move zero-depth anchor append to work like CFG and bias appends
|
||||||
|
if (zeroDepthAnchor && zeroDepthAnchor.length) {
|
||||||
|
if (!isMultigenEnabled() || tokens_already_generated == 0) {
|
||||||
|
console.log(/\s/.test(finalMesSend[finalMesSend.length - 1].message.slice(-1)))
|
||||||
|
finalMesSend[finalMesSend.length - 1].message +=
|
||||||
|
/\s/.test(finalMesSend[finalMesSend.length - 1].message.slice(-1))
|
||||||
|
? zeroDepthAnchor
|
||||||
|
: `${zeroDepthAnchor}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let cfgPrompt = {};
|
let cfgPrompt = {};
|
||||||
if (cfgGuidanceScale && cfgGuidanceScale?.value !== 1) {
|
if (cfgGuidanceScale && cfgGuidanceScale?.value !== 1) {
|
||||||
cfgPrompt = getCfgPrompt(cfgGuidanceScale, isNegative);
|
cfgPrompt = getCfgPrompt(cfgGuidanceScale, isNegative);
|
||||||
@ -2776,13 +2805,13 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
|
|
||||||
if (cfgPrompt && cfgPrompt?.value) {
|
if (cfgPrompt && cfgPrompt?.value) {
|
||||||
if (cfgPrompt?.depth === 0) {
|
if (cfgPrompt?.depth === 0) {
|
||||||
finalMesSend[finalMesSend.length - 1] +=
|
finalMesSend[finalMesSend.length - 1].message +=
|
||||||
/\s/.test(finalMesSend[finalMesSend.length - 1].slice(-1))
|
/\s/.test(finalMesSend[finalMesSend.length - 1].message.slice(-1))
|
||||||
? cfgPrompt.value
|
? cfgPrompt.value
|
||||||
: ` ${cfgPrompt.value}`;
|
: ` ${cfgPrompt.value}`;
|
||||||
} else {
|
} else {
|
||||||
// TODO: Make all extension prompts use an array/splice method
|
// TODO: Make all extension prompts use an array/splice method
|
||||||
finalMesSend.splice(mesSend.length - cfgPrompt.depth, 0, `${cfgPrompt.value}\n`);
|
finalMesSend[mesSend.length - cfgPrompt.depth].extensionPrompts.push(`${cfgPrompt.value}\n`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2790,25 +2819,20 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
// Always run with continue
|
// Always run with continue
|
||||||
if (!isInstruct && !isImpersonate && (tokens_already_generated === 0 || isContinue)) {
|
if (!isInstruct && !isImpersonate && (tokens_already_generated === 0 || isContinue)) {
|
||||||
if (promptBias.trim().length !== 0) {
|
if (promptBias.trim().length !== 0) {
|
||||||
finalMesSend[finalMesSend.length - 1] +=
|
finalMesSend[finalMesSend.length - 1].message +=
|
||||||
/\s/.test(finalMesSend[finalMesSend.length - 1].slice(-1))
|
/\s/.test(finalMesSend[finalMesSend.length - 1].message.slice(-1))
|
||||||
? promptBias.trimStart()
|
? promptBias.trimStart()
|
||||||
: ` ${promptBias.trimStart()}`;
|
: ` ${promptBias.trimStart()}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Prune from prompt cache if it exists
|
// Prune from prompt cache if it exists
|
||||||
if (generatedPromtCache.length !== 0) {
|
if (generatedPromtCache.length !== 0) {
|
||||||
generatedPromtCache = cleanupPromptCache(generatedPromtCache);
|
generatedPromtCache = cleanupPromptCache(generatedPromtCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override for prompt bits data
|
// Right now, everything is suffixed with a newline
|
||||||
if (!isNegative) {
|
mesSendString = finalMesSend.map((e) => `${e.extensionPrompts.join('')}${e.message}`).join('');
|
||||||
mesSend = finalMesSend;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mesSendString = finalMesSend.join('');
|
|
||||||
|
|
||||||
// add chat preamble
|
// add chat preamble
|
||||||
mesSendString = addChatsPreamble(mesSendString);
|
mesSendString = addChatsPreamble(mesSendString);
|
||||||
@ -2823,13 +2847,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
mesSendString +
|
mesSendString +
|
||||||
generatedPromtCache;
|
generatedPromtCache;
|
||||||
|
|
||||||
// TODO: Move zero-depth anchor append to work like CFG and bias appends
|
|
||||||
if (zeroDepthAnchor && zeroDepthAnchor.length) {
|
|
||||||
if (!isMultigenEnabled() || tokens_already_generated == 0) {
|
|
||||||
combinedPrompt = appendZeroDepthAnchor(force_name2, zeroDepthAnchor, combinedPrompt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
combinedPrompt = combinedPrompt.replace(/\r/gm, '');
|
combinedPrompt = combinedPrompt.replace(/\r/gm, '');
|
||||||
|
|
||||||
if (power_user.collapse_newlines) {
|
if (power_user.collapse_newlines) {
|
||||||
@ -2841,7 +2858,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
|
|
||||||
// Get the negative prompt first since it has the unmodified mesSend array
|
// Get the negative prompt first since it has the unmodified mesSend array
|
||||||
let negativePrompt = main_api == 'textgenerationwebui' ? getCombinedPrompt(true) : undefined;
|
let negativePrompt = main_api == 'textgenerationwebui' ? getCombinedPrompt(true) : undefined;
|
||||||
let finalPromt = getCombinedPrompt(false);
|
let finalPrompt = getCombinedPrompt(false);
|
||||||
|
|
||||||
// Include the entire guidance scale object
|
// Include the entire guidance scale object
|
||||||
const cfgValues = cfgGuidanceScale && cfgGuidanceScale?.value !== 1 ? ({ guidanceScale: cfgGuidanceScale, negativePrompt: negativePrompt }) : null;
|
const cfgValues = cfgGuidanceScale && cfgGuidanceScale?.value !== 1 ? ({ guidanceScale: cfgGuidanceScale, negativePrompt: negativePrompt }) : null;
|
||||||
@ -2865,7 +2882,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
let generate_data;
|
let generate_data;
|
||||||
if (main_api == 'koboldhorde' || main_api == 'kobold') {
|
if (main_api == 'koboldhorde' || main_api == 'kobold') {
|
||||||
generate_data = {
|
generate_data = {
|
||||||
prompt: finalPromt,
|
prompt: finalPrompt,
|
||||||
gui_settings: true,
|
gui_settings: true,
|
||||||
max_length: amount_gen,
|
max_length: amount_gen,
|
||||||
temperature: kai_settings.temp,
|
temperature: kai_settings.temp,
|
||||||
@ -2875,16 +2892,16 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
|
|
||||||
if (preset_settings != 'gui') {
|
if (preset_settings != 'gui') {
|
||||||
const maxContext = (adjustedParams && horde_settings.auto_adjust_context_length) ? adjustedParams.maxContextLength : max_context;
|
const maxContext = (adjustedParams && horde_settings.auto_adjust_context_length) ? adjustedParams.maxContextLength : max_context;
|
||||||
generate_data = getKoboldGenerationData(finalPromt, this_settings, this_amount_gen, maxContext, isImpersonate, type);
|
generate_data = getKoboldGenerationData(finalPrompt, this_settings, this_amount_gen, maxContext, isImpersonate, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (main_api == 'textgenerationwebui') {
|
else if (main_api == 'textgenerationwebui') {
|
||||||
generate_data = getTextGenGenerationData(finalPromt, this_amount_gen, isImpersonate, cfgValues);
|
generate_data = getTextGenGenerationData(finalPrompt, this_amount_gen, isImpersonate, cfgValues);
|
||||||
generate_data.use_mancer = api_use_mancer_webui;
|
generate_data.use_mancer = api_use_mancer_webui;
|
||||||
}
|
}
|
||||||
else if (main_api == 'novel') {
|
else if (main_api == 'novel') {
|
||||||
const this_settings = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]];
|
const this_settings = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]];
|
||||||
generate_data = getNovelGenerationData(finalPromt, this_settings, this_amount_gen, isImpersonate, cfgValues);
|
generate_data = getNovelGenerationData(finalPrompt, this_settings, this_amount_gen, isImpersonate, cfgValues);
|
||||||
}
|
}
|
||||||
else if (main_api == 'openai') {
|
else if (main_api == 'openai') {
|
||||||
let [prompt, counts] = prepareOpenAIMessages({
|
let [prompt, counts] = prepareOpenAIMessages({
|
||||||
@ -2940,10 +2957,10 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
storyString: storyString,
|
storyString: storyString,
|
||||||
afterScenarioAnchor: afterScenarioAnchor,
|
afterScenarioAnchor: afterScenarioAnchor,
|
||||||
examplesString: examplesString,
|
examplesString: examplesString,
|
||||||
mesSendString: mesSend.join(''),
|
mesSendString: mesSendString,
|
||||||
generatedPromtCache: generatedPromtCache,
|
generatedPromtCache: generatedPromtCache,
|
||||||
promptBias: promptBias,
|
promptBias: promptBias,
|
||||||
finalPromt: finalPromt,
|
finalPromt: finalPrompt,
|
||||||
charDescription: charDescription,
|
charDescription: charDescription,
|
||||||
charPersonality: charPersonality,
|
charPersonality: charPersonality,
|
||||||
scenarioText: scenarioText,
|
scenarioText: scenarioText,
|
||||||
@ -2970,7 +2987,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (main_api == 'koboldhorde') {
|
else if (main_api == 'koboldhorde') {
|
||||||
generateHorde(finalPromt, generate_data, abortController.signal).then(onSuccess).catch(onError);
|
generateHorde(finalPrompt, generate_data, abortController.signal).then(onSuccess).catch(onError);
|
||||||
}
|
}
|
||||||
else if (main_api == 'textgenerationwebui' && isStreamingEnabled() && type !== 'quiet') {
|
else if (main_api == 'textgenerationwebui' && isStreamingEnabled() && type !== 'quiet') {
|
||||||
streamingProcessor.generator = await generateTextGenWithStreaming(generate_data, streamingProcessor.abortController.signal);
|
streamingProcessor.generator = await generateTextGenWithStreaming(generate_data, streamingProcessor.abortController.signal);
|
||||||
@ -5844,10 +5861,22 @@ function select_rm_characters() {
|
|||||||
printCharacters(false); // Do a quick refresh of the characters list
|
printCharacters(false); // Do a quick refresh of the characters list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a prompt injection to insert custom text into any outgoing prompt. For use in UI extensions.
|
||||||
|
* @param {string} key Prompt injection id.
|
||||||
|
* @param {string} value Prompt injection value.
|
||||||
|
* @param {number} position Insertion position. 0 is after story string, 1 is in-chat with custom depth.
|
||||||
|
* @param {number} depth Insertion depth. 0 represets the last message in context. Expected values up to 100.
|
||||||
|
*/
|
||||||
function setExtensionPrompt(key, value, position, depth) {
|
function setExtensionPrompt(key, value, position, depth) {
|
||||||
extension_prompts[key] = { value, position, depth };
|
extension_prompts[key] = { value: String(value), position: Number(position), depth: Number(depth) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds or updates the metadata for the currently active chat.
|
||||||
|
* @param {Object} newValues An object with collection of new values to be added into the metadata.
|
||||||
|
* @param {boolean} reset Should a metadata be reset by this call.
|
||||||
|
*/
|
||||||
function updateChatMetadata(newValues, reset) {
|
function updateChatMetadata(newValues, reset) {
|
||||||
chat_metadata = reset ? { ...newValues } : { ...chat_metadata, ...newValues };
|
chat_metadata = reset ? { ...newValues } : { ...chat_metadata, ...newValues };
|
||||||
}
|
}
|
||||||
@ -9035,5 +9064,6 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Added here to prevent execution before script.js is loaded and get rid of quirky timeouts
|
// Added here to prevent execution before script.js is loaded and get rid of quirky timeouts
|
||||||
|
initAuthorsNote();
|
||||||
initRossMods();
|
initRossMods();
|
||||||
});
|
});
|
||||||
|
@ -389,10 +389,11 @@ function onChatChanged() {
|
|||||||
$('#extension_floating_default_token_counter').text(tokenCounter3);
|
$('#extension_floating_default_token_counter').text(tokenCounter3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject extension when extensions_activating is fired
|
/**
|
||||||
|
* Inject author's note options and setup event listeners.
|
||||||
|
*/
|
||||||
// Inserts the extension first since it's statically imported
|
// Inserts the extension first since it's statically imported
|
||||||
jQuery(async () => {
|
export function initAuthorsNote() {
|
||||||
await waitUntilCondition(() => eventSource !== undefined);
|
|
||||||
$('#extension_floating_prompt').on('input', onExtensionFloatingPromptInput);
|
$('#extension_floating_prompt').on('input', onExtensionFloatingPromptInput);
|
||||||
$('#extension_floating_interval').on('input', onExtensionFloatingIntervalInput);
|
$('#extension_floating_interval').on('input', onExtensionFloatingIntervalInput);
|
||||||
$('#extension_floating_depth').on('input', onExtensionFloatingDepthInput);
|
$('#extension_floating_depth').on('input', onExtensionFloatingDepthInput);
|
||||||
@ -419,4 +420,4 @@ jQuery(async () => {
|
|||||||
registerSlashCommand('freq', setNoteIntervalCommand, ['interval'], "<span class='monospace'>(number)</span> – sets an author's note insertion frequency", true, true);
|
registerSlashCommand('freq', setNoteIntervalCommand, ['interval'], "<span class='monospace'>(number)</span> – sets an author's note insertion frequency", true, true);
|
||||||
registerSlashCommand('pos', setNotePositionCommand, ['position'], "(<span class='monospace'>chat</span> or <span class='monospace'>scenario</span>) – sets an author's note position", true, true);
|
registerSlashCommand('pos', setNotePositionCommand, ['position'], "(<span class='monospace'>chat</span> or <span class='monospace'>scenario</span>) – sets an author's note position", true, true);
|
||||||
eventSource.on(event_types.CHAT_CHANGED, onChatChanged);
|
eventSource.on(event_types.CHAT_CHANGED, onChatChanged);
|
||||||
});
|
}
|
||||||
|
@ -296,11 +296,11 @@ function setOpenAIMessages(chat) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add chat injections, 100 = maximum depth of injection. (Why would you ever need more?)
|
// Add chat injections, 100 = maximum depth of injection. (Why would you ever need more?)
|
||||||
for (let i = 0; i < 100; i++) {
|
for (let i = 100; i >= 0; i--) {
|
||||||
const anchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, i);
|
const anchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, i);
|
||||||
|
|
||||||
if (anchor && anchor.length) {
|
if (anchor && anchor.length) {
|
||||||
openai_msgs.splice(i, 0, { "role": 'system', 'content': anchor.trim() })
|
openai_msgs.splice(i, 0, { "role": 'system', 'content': anchor.trim() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user