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 | prefixSpan.text(prefix); | 88 | prefixSpan.text(prefix); |
| 89 | prefixSpan.html(prefixSpan.html().replace(/\n/g, '<br>')); | 89 | prefixSpan.html(prefixSpan.html().replace(/\n/g, '<br>')); |
| 90 | prefixSpan.addClass('logprobs_output_prefix'); | 90 | prefixSpan.addClass('logprobs_output_prefix'); |
| 91 | prefixSpan.attr('title', 'Select to reroll the last \'Continue\' generation'); | 91 | prefixSpan.attr('title', 'Select to reroll the last \'Continue\' generation.\nHold the CTRL key when clicking to reroll from before that word.'); |
| 92 | prefixSpan.click(onPrefixClicked); | 92 | prefixSpan.click(onPrefixClicked); |
| 93 | addKeyboardProps(prefixSpan); | 93 | addKeyboardProps(prefixSpan); |
| 94 | tokenSpans.push(...withVirtualWhitespace(prefix, prefixSpan)); | 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 | * onPrefixClicked is called when the user clicks on the carried-over prefix | 283 | * onPrefixClicked is called when the user clicks on the carried-over prefix |
| 247 | * in the token output view. It allows them to reroll the last 'continue' | 284 | * in the token output view. It allows them to reroll the last 'continue' |
| 248 | * completion with none of the output generated from it, in case they don't | 285 | * completion with none of the output generated from it, in case they don't |
| 249 | * like the results. | 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 | function onPrefixClicked() { | 291 | function onPrefixClicked() { |
| 252 | if (!checkGenerateReady()) { | 292 | if (!checkGenerateReady()) { |
| @@ -255,7 +295,15 @@ function onPrefixClicked() { | |||
| 255 | 295 | ||
| 256 | const { continueFrom } = getActiveMessageLogprobData(); | 296 | const { continueFrom } = getActiveMessageLogprobData(); |
| 257 | const messageId = chat.length - 1; | 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 | createSwipe(messageId, prefix); | 307 | createSwipe(messageId, prefix); |
| 260 | $('.swipe_right:last').click(); | 308 | $('.swipe_right:last').click(); |
| 261 | Generate('continue').then(_ => void _); | 309 | Generate('continue').then(_ => void _); |