Enhance Token Probabilities viewer with selective reroll functionality and text extraction helper - Updated onPrefixClicked() to add Ctrl-click functionality: - Default click rerolls the entire prefix text to continue the generation. - Ctrl-click rerolls only the text before the clicked word, allowing users to more precisely control generation output. - Introduced getTextBeforeClickedWord() helper function: - Extracts the text before a clicked word based on click coordinates, enhancing control over prefix selection. - Provides a fallback to return the entire span text if word extraction is not possible. - Updated function documentation to clarify new behaviors and helper purpose. This change allows users to reset the prefix at a certain point if needed, adding flexibility to the generation process and enabling more intentional selection of alternatives.
| @@ -88,7 +88,7 @@ function renderAlternativeTokensView() { | ||
| 88 | 88 | prefixSpan.text(prefix); |
| 89 | 89 | prefixSpan.html(prefixSpan.html().replace(/\n/g, '<br>')); |
| 90 | 90 | prefixSpan.addClass('logprobs_output_prefix'); |
| 91 | 91 | prefixSpan.attr('title', 'Select to reroll the last \'Continue\' generation.\nHold the CTRL key when clicking to reroll from before that word.'); |
| 92 | 92 | prefixSpan.click(onPrefixClicked); |
| 93 | 93 | addKeyboardProps(prefixSpan); |
| 94 | 94 | tokenSpans.push(...withVirtualWhitespace(prefix, prefixSpan)); |
| @@ -243,10 +243,50 @@ function onAlternativeClicked(tokenLogprobs, alternative) { | ||
| 243 | 243 | } |
| 244 | 244 | |
| 245 | 245 | /** |
| 246 | + * getTextBeforeClickedWord retrieves the portion of text within a span | |
| 247 | + * that appears before the word clicked by the user. Using the x and y | |
| 248 | + * coordinates from a PointerEvent, this function identifies the exact | |
| 249 | + * word clicked and returns the text preceding it within the span. | |
| 250 | + * | |
| 251 | + * If the clicked position does not resolve to a valid word or text node, | |
| 252 | + * the entire span text is returned as a fallback. | |
| 253 | + * | |
| 254 | + * @param {PointerEvent} event - The click event containing the x and y coordinates. | |
| 255 | + * @param {string} spanText - The full text content of the span element. | |
| 256 | + * @returns {string} The text before the clicked word, or the entire span text as fallback. | |
| 257 | + */ | |
| 258 | +function getTextBeforeClickedWord(event, spanText) { | |
| 259 | + const x = event.clientX; | |
| 260 | + const y = event.clientY; | |
| 261 | + const range = document.caretRangeFromPoint(x, y); | |
| 262 | + | |
| 263 | + if (range && range.startContainer.nodeType === Node.TEXT_NODE) { | |
| 264 | + const textNode = range.startContainer; | |
| 265 | + const offset = range.startOffset; | |
| 266 | + | |
| 267 | + // Get the full text content of the text node | |
| 268 | + const text = textNode.nodeValue; | |
| 269 | + | |
| 270 | + // Find the boundaries of the clicked word | |
| 271 | + const start = text.lastIndexOf(" ", offset - 1) + 1; | |
| 272 | + | |
| 273 | + // Return the text before the clicked word | |
| 274 | + return text.slice(0, start); | |
| 275 | + } | |
| 276 | + | |
| 277 | + // If we can't determine the exact word, return the full span text as a fallback | |
| 278 | + return spanText; | |
| 279 | +} | |
| 280 | + | |
| 281 | + | |
| 282 | +/** | |
| 246 | 283 | * onPrefixClicked is called when the user clicks on the carried-over prefix |
| 247 | 284 | * in the token output view. It allows them to reroll the last 'continue' |
| 248 | 285 | * completion with none of the output generated from it, in case they don't |
| 249 | 286 | * like the results. |
| 287 | + * | |
| 288 | + * If the user holds the Ctrl key while clicking, only the portion of text | |
| 289 | + * before the clicked word is retained as the prefix for rerolling | |
| 250 | 290 | */ |
| 251 | 291 | function onPrefixClicked() { |
| 252 | 292 | if (!checkGenerateReady()) { |
| @@ -255,7 +295,15 @@ function onPrefixClicked() { | ||
| 255 | 295 | |
| 256 | 296 | const { continueFrom } = getActiveMessageLogprobData(); |
| 257 | 297 | const messageId = chat.length - 1; |
| 258 | - const prefix = continueFrom || ''; | |
| 298 | + | |
| 299 | + // Check if Ctrl key is pressed during the click | |
| 300 | + let prefix = continueFrom || ''; | |
| 301 | + if (event.ctrlKey) { | |
| 302 | + // Ctrl is pressed - use the text before the clicked word | |
| 303 | + prefix = getTextBeforeClickedWord(event, continueFrom); | |
| 304 | + } | |
| 305 | + | |
| 306 | + // Use the determined `prefix` | |
| 259 | 307 | createSwipe(messageId, prefix); |
| 260 | 308 | $('.swipe_right:last').click(); |
| 261 | 309 | Generate('continue').then(_ => void _); |