Make dynamic reroll available without use of modifier key
Linting
This commit is contained in:
parent
7c7aaf33fc
commit
5e883e446a
|
@ -72,6 +72,20 @@
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logprobs_output_prefix:hover {
|
||||||
|
background-color: rgba(255, 0, 50, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logprobs_output_prefix:hover ~ .logprobs_output_prefix {
|
||||||
|
background-color: rgba(255, 0, 50, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#logprobsReroll {
|
||||||
|
float: right; /* Position the button to the right */
|
||||||
|
margin: 5px 0 5px 10px; /* Add spacing (top, right, bottom, left) */
|
||||||
|
clear: right; /* Ensure it starts on a new line */
|
||||||
|
}
|
||||||
|
|
||||||
.logprobs_candidate_list {
|
.logprobs_candidate_list {
|
||||||
grid-row-start: 3;
|
grid-row-start: 3;
|
||||||
grid-row-end: 4;
|
grid-row-end: 4;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import {
|
import {
|
||||||
animation_duration,
|
animation_duration,
|
||||||
callPopup,
|
|
||||||
chat,
|
chat,
|
||||||
cleanUpMessage,
|
cleanUpMessage,
|
||||||
event_types,
|
event_types,
|
||||||
|
@ -13,6 +12,8 @@ import {
|
||||||
import { debounce, delay, getStringHash } from './utils.js';
|
import { debounce, delay, getStringHash } from './utils.js';
|
||||||
import { decodeTextTokens, getTokenizerBestMatch } from './tokenizers.js';
|
import { decodeTextTokens, getTokenizerBestMatch } from './tokenizers.js';
|
||||||
import { power_user } from './power-user.js';
|
import { power_user } from './power-user.js';
|
||||||
|
import { callGenericPopup, POPUP_TYPE } from './popup.js';
|
||||||
|
import { t } from './i18n.js';
|
||||||
|
|
||||||
const TINTS = 4;
|
const TINTS = 4;
|
||||||
const MAX_MESSAGE_LOGPROBS = 100;
|
const MAX_MESSAGE_LOGPROBS = 100;
|
||||||
|
@ -43,17 +44,26 @@ const MAX_MESSAGE_LOGPROBS = 100;
|
||||||
* @property {Candidate[]} topLogprobs - Array of top candidate tokens
|
* @property {Candidate[]} topLogprobs - Array of top candidate tokens
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let state = {
|
/**
|
||||||
/** @type {TokenLogprobs | null} */
|
* State object for Token Probabilities
|
||||||
|
* @typedef {Object} LogprobsState
|
||||||
|
* @property {?TokenLogprobs} selectedTokenLogprobs Log probabilities for
|
||||||
|
* currently-selected token.
|
||||||
|
* @property {Map<number, MessageLogprobData>} messageLogprobs Log probabilities for
|
||||||
|
* each message, keyed by message hash.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {LogprobsState} state
|
||||||
|
*/
|
||||||
|
const state = {
|
||||||
selectedTokenLogprobs: null,
|
selectedTokenLogprobs: null,
|
||||||
/** @type {Map<number, MessageLogprobData>} */
|
|
||||||
messageLogprobs: new Map(),
|
messageLogprobs: new Map(),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* renderAlternativeTokensView renders the Token Probabilities UI and all
|
* Renders the Token Probabilities UI and all subviews with the active message's
|
||||||
* subviews with the active message's logprobs data. If the message has no token
|
* logprobs data. If the message has no token logprobs, a message is displayed.
|
||||||
* logprobs, a zero-state is rendered.
|
|
||||||
*/
|
*/
|
||||||
function renderAlternativeTokensView() {
|
function renderAlternativeTokensView() {
|
||||||
const view = $('#logprobs_generation_output');
|
const view = $('#logprobs_generation_output');
|
||||||
|
@ -68,13 +78,14 @@ function renderAlternativeTokensView() {
|
||||||
const usingSmoothStreaming = isStreamingEnabled() && power_user.smooth_streaming;
|
const usingSmoothStreaming = isStreamingEnabled() && power_user.smooth_streaming;
|
||||||
if (!messageLogprobs?.length || usingSmoothStreaming) {
|
if (!messageLogprobs?.length || usingSmoothStreaming) {
|
||||||
const emptyState = $('<div></div>');
|
const emptyState = $('<div></div>');
|
||||||
const noTokensMsg = usingSmoothStreaming
|
const noTokensMsg = !power_user.request_token_probabilities
|
||||||
? 'Token probabilities are not available when using Smooth Streaming.'
|
? '<span>Enable <b>Request token probabilities</b> in the User Settings menu to use this feature.</span>'
|
||||||
: 'No token probabilities available for the current message.';
|
: usingSmoothStreaming
|
||||||
const msg = power_user.request_token_probabilities
|
? t`Token probabilities are not available when using Smooth Streaming.`
|
||||||
? noTokensMsg
|
: is_send_press
|
||||||
: '<span>Enable <b>Request token probabilities</b> in the User Settings menu to use this feature.</span>';
|
? t`Generation in progress...`
|
||||||
emptyState.html(msg);
|
: t`No token probabilities available for the current message.`;
|
||||||
|
emptyState.html(noTokensMsg);
|
||||||
emptyState.addClass('logprobs_empty_state');
|
emptyState.addClass('logprobs_empty_state');
|
||||||
view.append(emptyState);
|
view.append(emptyState);
|
||||||
return;
|
return;
|
||||||
|
@ -84,16 +95,39 @@ function renderAlternativeTokensView() {
|
||||||
const tokenSpans = [];
|
const tokenSpans = [];
|
||||||
|
|
||||||
if (prefix) {
|
if (prefix) {
|
||||||
const prefixSpan = $('<span></span>');
|
const rerollButton = $('<button id="logprobsReroll" class="menu_button">' +
|
||||||
prefixSpan.text(prefix);
|
' <span class="fa-solid fa-redo logprobs_reroll"></span>' +
|
||||||
prefixSpan.html(prefixSpan.html().replace(/\n/g, '<br>'));
|
'</button>');
|
||||||
prefixSpan.addClass('logprobs_output_prefix');
|
rerollButton.attr('title', t`Reroll with the entire prefix`);
|
||||||
prefixSpan.attr('title', 'Select to reroll the last \'Continue\' generation.\nHold the CTRL key when clicking to reroll from before that word.');
|
rerollButton.on('click', () => onPrefixClicked(prefix.length));
|
||||||
prefixSpan.click(onPrefixClicked);
|
tokenSpans.push(rerollButton);
|
||||||
addKeyboardProps(prefixSpan);
|
|
||||||
tokenSpans.push(...withVirtualWhitespace(prefix, prefixSpan));
|
let cumulativeOffset = 0;
|
||||||
|
const words = prefix.split(/\s+/);
|
||||||
|
const delimiters = prefix.match(/\s+/g) || []; // Capture the actual delimiters
|
||||||
|
|
||||||
|
words.forEach((word, i) => {
|
||||||
|
const span = $('<span></span>');
|
||||||
|
span.text(`${word} `);
|
||||||
|
|
||||||
|
span.addClass('logprobs_output_prefix');
|
||||||
|
span.attr('title', t`Reroll from this point`);
|
||||||
|
|
||||||
|
let offset = cumulativeOffset;
|
||||||
|
span.on('click', () => onPrefixClicked(offset));
|
||||||
|
addKeyboardProps(span);
|
||||||
|
|
||||||
|
tokenSpans.push(span);
|
||||||
|
tokenSpans.push(delimiters[i]?.includes('\n')
|
||||||
|
? document.createElement('br')
|
||||||
|
: document.createTextNode(delimiters[i] || ' '),
|
||||||
|
);
|
||||||
|
|
||||||
|
cumulativeOffset += word.length + (delimiters[i]?.length || 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
messageLogprobs.forEach((tokenData, i) => {
|
messageLogprobs.forEach((tokenData, i) => {
|
||||||
const { token } = tokenData;
|
const { token } = tokenData;
|
||||||
const span = $('<span></span>');
|
const span = $('<span></span>');
|
||||||
|
@ -101,7 +135,7 @@ function renderAlternativeTokensView() {
|
||||||
span.text(text);
|
span.text(text);
|
||||||
span.addClass('logprobs_output_token');
|
span.addClass('logprobs_output_token');
|
||||||
span.addClass('logprobs_tint_' + (i % TINTS));
|
span.addClass('logprobs_tint_' + (i % TINTS));
|
||||||
span.click(() => onSelectedTokenChanged(tokenData, span));
|
span.on('click', () => onSelectedTokenChanged(tokenData, span));
|
||||||
addKeyboardProps(span);
|
addKeyboardProps(span);
|
||||||
tokenSpans.push(...withVirtualWhitespace(token, span));
|
tokenSpans.push(...withVirtualWhitespace(token, span));
|
||||||
});
|
});
|
||||||
|
@ -129,6 +163,10 @@ function addKeyboardProps(element) {
|
||||||
/**
|
/**
|
||||||
* renderTopLogprobs renders the top logprobs subview with the currently
|
* renderTopLogprobs renders the top logprobs subview with the currently
|
||||||
* selected token highlighted. If no token is selected, the subview is hidden.
|
* selected token highlighted. If no token is selected, the subview is hidden.
|
||||||
|
*
|
||||||
|
* Callers:
|
||||||
|
* - renderAlternativeTokensView, to render the entire view
|
||||||
|
* - onSelectedTokenChanged, to update the view when a token is selected
|
||||||
*/
|
*/
|
||||||
function renderTopLogprobs() {
|
function renderTopLogprobs() {
|
||||||
$('#logprobs_top_logprobs_hint').hide();
|
$('#logprobs_top_logprobs_hint').hide();
|
||||||
|
@ -150,8 +188,7 @@ function renderTopLogprobs() {
|
||||||
const probability = Math.exp(log);
|
const probability = Math.exp(log);
|
||||||
sum += probability;
|
sum += probability;
|
||||||
return [text, probability, log];
|
return [text, probability, log];
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return [text, log, null];
|
return [text, log, null];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -175,7 +212,7 @@ function renderTopLogprobs() {
|
||||||
}
|
}
|
||||||
addKeyboardProps(container);
|
addKeyboardProps(container);
|
||||||
if (token !== '<others>') {
|
if (token !== '<others>') {
|
||||||
container.click(() => onAlternativeClicked(state.selectedTokenLogprobs, token));
|
container.on('click', () => onAlternativeClicked(state.selectedTokenLogprobs, token));
|
||||||
} else {
|
} else {
|
||||||
container.prop('disabled', true);
|
container.prop('disabled', true);
|
||||||
}
|
}
|
||||||
|
@ -192,9 +229,8 @@ function renderTopLogprobs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onSelectedTokenChanged is called when the user clicks on a token in the
|
* User clicks on a token in the token output view. It updates the selected token state
|
||||||
* token output view. It updates the selected token state and re-renders the
|
* and re-renders the top logprobs view, or deselects the token if it was already selected.
|
||||||
* top logprobs view, or deselects the token if it was already selected.
|
|
||||||
* @param {TokenLogprobs} logprobs - logprob data for the selected token
|
* @param {TokenLogprobs} logprobs - logprob data for the selected token
|
||||||
* @param {Element} span - target span node that was clicked
|
* @param {Element} span - target span node that was clicked
|
||||||
*/
|
*/
|
||||||
|
@ -223,7 +259,10 @@ function onAlternativeClicked(tokenLogprobs, alternative) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getGeneratingApi() === 'openai') {
|
if (getGeneratingApi() === 'openai') {
|
||||||
return callPopup('<h3>Feature unavailable</h3><p>Due to API limitations, rerolling a token is not supported with OpenAI. Try switching to a different API.</p>', 'text');
|
const title = t`Feature unavailable`;
|
||||||
|
const message = t`Due to API limitations, rerolling a token is not supported with OpenAI. Try switching to a different API.`;
|
||||||
|
const content = `<h3>${title}</h3><p>${message}</p>`;
|
||||||
|
return callGenericPopup(content, POPUP_TYPE.TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { messageLogprobs, continueFrom } = getActiveMessageLogprobData();
|
const { messageLogprobs, continueFrom } = getActiveMessageLogprobData();
|
||||||
|
@ -234,79 +273,29 @@ function onAlternativeClicked(tokenLogprobs, alternative) {
|
||||||
|
|
||||||
const prefix = continueFrom || '';
|
const prefix = continueFrom || '';
|
||||||
const prompt = prefix + tokens.join('');
|
const prompt = prefix + tokens.join('');
|
||||||
const messageId = chat.length - 1;
|
addGeneration(prompt);
|
||||||
createSwipe(messageId, prompt);
|
|
||||||
|
|
||||||
$('.swipe_right:last').click(); // :see_no_evil:
|
|
||||||
|
|
||||||
Generate('continue').then(_ => void _);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getTextBeforeClickedWord retrieves the portion of text within a span
|
* User clicks on the reroll button in the token output view, or on a word in the
|
||||||
* that appears before the word clicked by the user. Using the x and y
|
* prefix. Retrieve the prefix for the current message and truncate it at the
|
||||||
* coordinates from a PointerEvent, this function identifies the exact
|
* offset for the selected word. Then request a `continue` completion from the
|
||||||
* word clicked and returns the text preceding it within the span.
|
* model with the new prompt.
|
||||||
*
|
*
|
||||||
* If the clicked position does not resolve to a valid word or text node,
|
* If no offset is provided, the entire prefix will be rerolled.
|
||||||
* the entire span text is returned as a fallback.
|
|
||||||
*
|
*
|
||||||
* @param {PointerEvent} event - The click event containing the x and y coordinates.
|
* @param {number} offset - index of the token in the prefix to reroll from
|
||||||
* @param {string} spanText - The full text content of the span element.
|
* @returns {void}
|
||||||
* @returns {string} The text before the clicked word, or the entire span text as fallback.
|
* @param offset
|
||||||
*/
|
*/
|
||||||
function getTextBeforeClickedWord(event, spanText) {
|
function onPrefixClicked(offset = undefined) {
|
||||||
const x = event.clientX;
|
|
||||||
const y = event.clientY;
|
|
||||||
const range = document.caretRangeFromPoint(x, y);
|
|
||||||
|
|
||||||
if (range && range.startContainer.nodeType === Node.TEXT_NODE) {
|
|
||||||
const textNode = range.startContainer;
|
|
||||||
const offset = range.startOffset;
|
|
||||||
|
|
||||||
// Get the full text content of the text node
|
|
||||||
const text = textNode.nodeValue;
|
|
||||||
|
|
||||||
// Find the boundaries of the clicked word
|
|
||||||
const start = text.lastIndexOf(' ', offset - 1) + 1;
|
|
||||||
|
|
||||||
// Return the text before the clicked word
|
|
||||||
return text.slice(0, start);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we can't determine the exact word, return the full span text as a fallback
|
|
||||||
return spanText;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* onPrefixClicked is called when the user clicks on the carried-over prefix
|
|
||||||
* in the token output view. It allows them to reroll the last 'continue'
|
|
||||||
* completion with none of the output generated from it, in case they don't
|
|
||||||
* like the results.
|
|
||||||
*
|
|
||||||
* If the user holds the Ctrl key while clicking, only the portion of text
|
|
||||||
* before the clicked word is retained as the prefix for rerolling
|
|
||||||
*/
|
|
||||||
function onPrefixClicked() {
|
|
||||||
if (!checkGenerateReady()) {
|
if (!checkGenerateReady()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { continueFrom } = getActiveMessageLogprobData();
|
const { continueFrom } = getActiveMessageLogprobData() || {};
|
||||||
const messageId = chat.length - 1;
|
const prefix = continueFrom ? continueFrom.substring(0, offset) : '';
|
||||||
|
addGeneration(prefix);
|
||||||
// Check if Ctrl key is pressed during the click
|
|
||||||
let prefix = continueFrom || '';
|
|
||||||
if (event.ctrlKey) {
|
|
||||||
// Ctrl is pressed - use the text before the clicked word
|
|
||||||
prefix = getTextBeforeClickedWord(event, continueFrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the determined `prefix`
|
|
||||||
createSwipe(messageId, prefix);
|
|
||||||
$('.swipe_right:last').click();
|
|
||||||
Generate('continue').then(_ => void _);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkGenerateReady() {
|
function checkGenerateReady() {
|
||||||
|
@ -317,6 +306,22 @@ function checkGenerateReady() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new swipe as a continuation of the given prompt, when user selects
|
||||||
|
* an alternative token or rerolls from a prefix.
|
||||||
|
*
|
||||||
|
* @param prompt
|
||||||
|
*/
|
||||||
|
function addGeneration(prompt) {
|
||||||
|
const messageId = chat.length - 1;
|
||||||
|
if (prompt && prompt.length > 0) {
|
||||||
|
createSwipe(messageId, prompt);
|
||||||
|
$('.swipe_right:last').trigger('click');
|
||||||
|
void Generate('continue');
|
||||||
|
} else {
|
||||||
|
$('.swipe_right:last').trigger('click');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onToggleLogprobsPanel is called when the user performs an action that toggles
|
* onToggleLogprobsPanel is called when the user performs an action that toggles
|
||||||
|
@ -356,8 +361,7 @@ function onToggleLogprobsPanel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* createSwipe appends a new swipe to the target chat message with the given
|
* Appends a new swipe to the target chat message with the given text.
|
||||||
* text.
|
|
||||||
* @param {number} messageId - target chat message ID
|
* @param {number} messageId - target chat message ID
|
||||||
* @param {string} prompt - initial prompt text which will be continued
|
* @param {string} prompt - initial prompt text which will be continued
|
||||||
*/
|
*/
|
||||||
|
@ -400,9 +404,10 @@ function toVisibleWhitespace(input) {
|
||||||
* allow text to wrap despite whitespace characters being replaced with a dot.
|
* allow text to wrap despite whitespace characters being replaced with a dot.
|
||||||
* @param {string} text - token text being evaluated for whitespace
|
* @param {string} text - token text being evaluated for whitespace
|
||||||
* @param {Element} span - target span node to be wrapped
|
* @param {Element} span - target span node to be wrapped
|
||||||
* @returns {Element[]} array of nodes to be appended to the DOM
|
* @returns {Node[]} - array of nodes to be appended to the parent element
|
||||||
*/
|
*/
|
||||||
function withVirtualWhitespace(text, span) {
|
function withVirtualWhitespace(text, span) {
|
||||||
|
/** @type {Node[]} */
|
||||||
const result = [span];
|
const result = [span];
|
||||||
if (text.match(/^\s/)) {
|
if (text.match(/^\s/)) {
|
||||||
result.unshift(document.createTextNode('\u200b'));
|
result.unshift(document.createTextNode('\u200b'));
|
||||||
|
@ -430,12 +435,16 @@ function withVirtualWhitespace(text, span) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* saveLogprobsForActiveMessage receives an array of TokenLogprobs objects
|
* Receives the top logprobs for each token in a message and associates it with the active message.
|
||||||
* representing the top logprobs for each token in a message and associates it
|
*
|
||||||
* with the active message.
|
* Ensure the active message has been updated and rendered before calling this function
|
||||||
|
* or the logprobs data will be saved to the wrong message.
|
||||||
|
*
|
||||||
|
* Callers:
|
||||||
|
* - Generate:onSuccess via saveLogprobsForActiveMessage, for non-streaming text completion
|
||||||
|
* - StreamingProcessor:onFinishStreaming, for streaming text completion
|
||||||
|
* - sendOpenAIRequest, for non-streaming chat completion
|
||||||
*
|
*
|
||||||
* **Ensure the active message has been updated and rendered before calling
|
|
||||||
* this function or the logprobs data will be saved to the wrong message.**
|
|
||||||
* @param {TokenLogprobs[]} logprobs - array of logprobs data for each token
|
* @param {TokenLogprobs[]} logprobs - array of logprobs data for each token
|
||||||
* @param {string | null} continueFrom - for 'continue' generations, the prompt
|
* @param {string | null} continueFrom - for 'continue' generations, the prompt
|
||||||
*/
|
*/
|
||||||
|
@ -445,7 +454,10 @@ export function saveLogprobsForActiveMessage(logprobs, continueFrom) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NovelAI only returns token IDs in logprobs data; convert to text tokens in-place
|
||||||
|
if (getGeneratingApi() === 'novel') {
|
||||||
convertTokenIdLogprobsToText(logprobs);
|
convertTokenIdLogprobsToText(logprobs);
|
||||||
|
}
|
||||||
|
|
||||||
const msgId = chat.length - 1;
|
const msgId = chat.length - 1;
|
||||||
/** @type {MessageLogprobData} */
|
/** @type {MessageLogprobData} */
|
||||||
|
@ -491,17 +503,18 @@ function getActiveMessageLogprobData() {
|
||||||
return state.messageLogprobs.get(hash) || null;
|
return state.messageLogprobs.get(hash) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convertLogprobTokenIdsToText mutates the given logprobs data's topLogprobs
|
* convertLogprobTokenIdsToText replaces token IDs in logprobs data with text tokens,
|
||||||
* field keyed by token text instead of token ID. This is only necessary for
|
* for APIs that return token IDs instead of text tokens, to wit: NovelAI.
|
||||||
* APIs which only return token IDs in their logprobs data; for others this
|
*
|
||||||
* function is a no-op.
|
|
||||||
* @param {TokenLogprobs[]} input - logprobs data with numeric token IDs
|
* @param {TokenLogprobs[]} input - logprobs data with numeric token IDs
|
||||||
*/
|
*/
|
||||||
function convertTokenIdLogprobsToText(input) {
|
function convertTokenIdLogprobsToText(input) {
|
||||||
const api = getGeneratingApi();
|
const api = getGeneratingApi();
|
||||||
if (api !== 'novel') {
|
if (api !== 'novel') {
|
||||||
return input;
|
// should have been checked by the caller
|
||||||
|
throw new Error('convertTokenIdLogprobsToText should only be called for NovelAI');
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokenizerId = getTokenizerBestMatch(api);
|
const tokenizerId = getTokenizerBestMatch(api);
|
||||||
|
@ -512,6 +525,7 @@ function convertTokenIdLogprobsToText(input) {
|
||||||
)));
|
)));
|
||||||
|
|
||||||
// Submit token IDs to tokenizer to get token text, then build ID->text map
|
// Submit token IDs to tokenizer to get token text, then build ID->text map
|
||||||
|
// noinspection JSCheckFunctionSignatures - mutates input in-place
|
||||||
const { chunks } = decodeTextTokens(tokenizerId, tokenIds);
|
const { chunks } = decodeTextTokens(tokenizerId, tokenIds);
|
||||||
const tokenIdText = new Map(tokenIds.map((id, i) => [id, chunks[i]]));
|
const tokenIdText = new Map(tokenIds.map((id, i) => [id, chunks[i]]));
|
||||||
|
|
||||||
|
@ -526,8 +540,8 @@ function convertTokenIdLogprobsToText(input) {
|
||||||
|
|
||||||
export function initLogprobs() {
|
export function initLogprobs() {
|
||||||
const debouncedRender = debounce(renderAlternativeTokensView);
|
const debouncedRender = debounce(renderAlternativeTokensView);
|
||||||
$('#logprobsViewerClose').click(onToggleLogprobsPanel);
|
$('#logprobsViewerClose').on('click', onToggleLogprobsPanel);
|
||||||
$('#option_toggle_logprobs').click(onToggleLogprobsPanel);
|
$('#option_toggle_logprobs').on('click', onToggleLogprobsPanel);
|
||||||
eventSource.on(event_types.CHAT_CHANGED, debouncedRender);
|
eventSource.on(event_types.CHAT_CHANGED, debouncedRender);
|
||||||
eventSource.on(event_types.CHARACTER_MESSAGE_RENDERED, debouncedRender);
|
eventSource.on(event_types.CHARACTER_MESSAGE_RENDERED, debouncedRender);
|
||||||
eventSource.on(event_types.IMPERSONATE_READY, debouncedRender);
|
eventSource.on(event_types.IMPERSONATE_READY, debouncedRender);
|
||||||
|
|
Loading…
Reference in New Issue