Merge pull request #3099 from ceruleandeep/fix/connRefusedErrMsg Fix/conn refused err msg
Signed| @@ -2705,8 +2705,7 @@ export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, q | |||
| 2705 | quietName: quietName, | 2705 | quietName: quietName, |
| 2706 | }; | 2706 | }; |
| 2707 | originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1; | 2707 | originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1; |
| 2708 | const generateFinished = await Generate('quiet', options); | 2708 | return await Generate('quiet', options); |
| 2709 | return generateFinished; | ||
| 2710 | } finally { | 2709 | } finally { |
| 2711 | if (responseLengthCustomized) { | 2710 | if (responseLengthCustomized) { |
| 2712 | restoreResponseLength(main_api, originalResponseLength); | 2711 | restoreResponseLength(main_api, originalResponseLength); |
| @@ -3361,9 +3360,9 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | |||
| 3361 | 3360 | ||
| 3362 | let data = {}; | 3361 | let data = {}; |
| 3363 | 3362 | ||
| 3364 | if (api == 'koboldhorde') { | 3363 | if (api === 'koboldhorde') { |
| 3365 | data = await generateHorde(prompt, generateData, abortController.signal, false); | 3364 | data = await generateHorde(prompt, generateData, abortController.signal, false); |
| 3366 | } else if (api == 'openai') { | 3365 | } else if (api === 'openai') { |
| 3367 | data = await sendOpenAIRequest('quiet', generateData, abortController.signal); | 3366 | data = await sendOpenAIRequest('quiet', generateData, abortController.signal); |
| 3368 | } else { | 3367 | } else { |
| 3369 | const generateUrl = getGenerateUrl(api); | 3368 | const generateUrl = getGenerateUrl(api); |
| @@ -3376,13 +3375,15 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | |||
| 3376 | }); | 3375 | }); |
| 3377 | 3376 | ||
| 3378 | if (!response.ok) { | 3377 | if (!response.ok) { |
| 3379 | const error = await response.json(); | 3378 | throw await response.json(); |
| 3380 | throw error; | ||
| 3381 | } | 3379 | } |
| 3382 | 3380 | ||
| 3383 | data = await response.json(); | 3381 | data = await response.json(); |
| 3384 | } | 3382 | } |
| 3385 | 3383 | ||
| 3384 | // should only happen for text completions | ||
| 3385 | // other frontend paths do not return data if calling the backend fails, | ||
| 3386 | // they throw things instead | ||
| 3386 | if (data.error) { | 3387 | if (data.error) { |
| 3387 | throw new Error(data.response); | 3388 | throw new Error(data.response); |
| 3388 | } | 3389 | } |
| @@ -4434,6 +4435,11 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4434 | return Promise.resolve(); | 4435 | return Promise.resolve(); |
| 4435 | } | 4436 | } |
| 4436 | 4437 | ||
| 4438 | /** | ||
| 4439 | * Saves itemized prompt bits and calls streaming or non-streaming generation API. | ||
| 4440 | * @returns {Promise<void|*|Awaited<*>|String|{fromStream}|string|undefined|Object>} | ||
| 4441 | * @throws {Error|object} Error with message text, or Error with response JSON (OAI/Horde), or the actual response JSON (novel|textgenerationwebui|kobold) | ||
| 4442 | */ | ||
| 4437 | async function finishGenerating() { | 4443 | async function finishGenerating() { |
| 4438 | if (power_user.console_log_prompts) { | 4444 | if (power_user.console_log_prompts) { |
| 4439 | console.log(generate_data.prompt); | 4445 | console.log(generate_data.prompt); |
| @@ -4545,6 +4551,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4545 | 4551 | ||
| 4546 | return finishGenerating().then(onSuccess, onError); | 4552 | return finishGenerating().then(onSuccess, onError); |
| 4547 | 4553 | ||
| 4554 | /** | ||
| 4555 | * Handles the successful response from the generation API. | ||
| 4556 | * @param data | ||
| 4557 | * @returns {Promise<String|{fromStream}|*|string|string|void|Awaited<*>|undefined>} | ||
| 4558 | * @throws {Error} Throws an error if the response data contains an error message | ||
| 4559 | */ | ||
| 4548 | async function onSuccess(data) { | 4560 | async function onSuccess(data) { |
| 4549 | if (!data) return; | 4561 | if (!data) return; |
| 4550 | 4562 | ||
| @@ -4554,6 +4566,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4554 | 4566 | ||
| 4555 | let messageChunk = ''; | 4567 | let messageChunk = ''; |
| 4556 | 4568 | ||
| 4569 | // if an error was returned in data (textgenwebui), show it and throw it | ||
| 4557 | if (data.error) { | 4570 | if (data.error) { |
| 4558 | unblockGeneration(type); | 4571 | unblockGeneration(type); |
| 4559 | generatedPromptCache = ''; | 4572 | generatedPromptCache = ''; |
| @@ -4668,9 +4681,15 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4668 | return Object.defineProperty(new String(getMessage), 'messageChunk', { value: messageChunk }); | 4681 | return Object.defineProperty(new String(getMessage), 'messageChunk', { value: messageChunk }); |
| 4669 | } | 4682 | } |
| 4670 | 4683 | ||
| 4684 | /** | ||
| 4685 | * Exception handler for finishGenerating | ||
| 4686 | * @param {Error|object} exception Error or response JSON | ||
| 4687 | * @throws {Error|object} Re-throws the exception | ||
| 4688 | */ | ||
| 4671 | function onError(exception) { | 4689 | function onError(exception) { |
| 4690 | // if the response JSON was thrown (novel|textgenerationwebui|kobold), show the error message | ||
| 4672 | if (typeof exception?.error?.message === 'string') { | 4691 | if (typeof exception?.error?.message === 'string') { |
| 4673 | toastr.error(exception.error.message, t`Error`, { timeOut: 10000, extendedTimeOut: 20000 }); | 4692 | toastr.error(exception.error.message, t`Text generation error`, { timeOut: 10000, extendedTimeOut: 20000 }); |
| 4674 | } | 4693 | } |
| 4675 | 4694 | ||
| 4676 | generatedPromptCache = ''; | 4695 | generatedPromptCache = ''; |
| @@ -5338,6 +5357,7 @@ function setInContextMessages(lastmsg, type) { | |||
| 5338 | * @param {string} type Generation type | 5357 | * @param {string} type Generation type |
| 5339 | * @param {object} data Generation data | 5358 | * @param {object} data Generation data |
| 5340 | * @returns {Promise<object>} Response data from the API | 5359 | * @returns {Promise<object>} Response data from the API |
| 5360 | * @throws {Error|object} | ||
| 5341 | */ | 5361 | */ |
| 5342 | export async function sendGenerationRequest(type, data) { | 5362 | export async function sendGenerationRequest(type, data) { |
| 5343 | if (main_api === 'openai') { | 5363 | if (main_api === 'openai') { |
| @@ -5357,12 +5377,10 @@ export async function sendGenerationRequest(type, data) { | |||
| 5357 | }); | 5377 | }); |
| 5358 | 5378 | ||
| 5359 | if (!response.ok) { | 5379 | if (!response.ok) { |
| 5360 | const error = await response.json(); | 5380 | throw await response.json(); |
| 5361 | throw error; | ||
| 5362 | } | 5381 | } |
| 5363 | 5382 | ||
| 5364 | const responseData = await response.json(); | 5383 | return await response.json(); |
| 5365 | return responseData; | ||
| 5366 | } | 5384 | } |
| 5367 | 5385 | ||
| 5368 | /** | 5386 | /** |
| @@ -5394,6 +5412,7 @@ export async function sendStreamingRequest(type, data) { | |||
| 5394 | * Gets the generation endpoint URL for the specified API. | 5412 | * Gets the generation endpoint URL for the specified API. |
| 5395 | * @param {string} api API name | 5413 | * @param {string} api API name |
| 5396 | * @returns {string} Generation URL | 5414 | * @returns {string} Generation URL |
| 5415 | * @throws {Error} If the API is unknown | ||
| 5397 | */ | 5416 | */ |
| 5398 | function getGenerateUrl(api) { | 5417 | function getGenerateUrl(api) { |
| 5399 | switch (api) { | 5418 | switch (api) { |
| @@ -2373,6 +2373,7 @@ function ensureSelectionExists(setting, selector) { | |||
| 2373 | * @param {string} [message] Chat message | 2373 | * @param {string} [message] Chat message |
| 2374 | * @param {function} [callback] Callback function | 2374 | * @param {function} [callback] Callback function |
| 2375 | * @returns {Promise<string|undefined>} Image path | 2375 | * @returns {Promise<string|undefined>} Image path |
| 2376 | * @throws {Error} If the prompt or image generation fails | ||
| 2376 | */ | 2377 | */ |
| 2377 | async function generatePicture(initiator, args, trigger, message, callback) { | 2378 | async function generatePicture(initiator, args, trigger, message, callback) { |
| 2378 | if (!trigger || trigger.trim().length === 0) { | 2379 | if (!trigger || trigger.trim().length === 0) { |
| @@ -2391,7 +2392,7 @@ async function generatePicture(initiator, args, trigger, message, callback) { | |||
| 2391 | trigger = trigger.trim(); | 2392 | trigger = trigger.trim(); |
| 2392 | const generationType = getGenerationType(trigger); | 2393 | const generationType = getGenerationType(trigger); |
| 2393 | const generationTypeKey = Object.keys(generationMode).find(key => generationMode[key] === generationType); | 2394 | const generationTypeKey = Object.keys(generationMode).find(key => generationMode[key] === generationType); |
| 2394 | console.log(`Generation mode ${generationTypeKey} triggered with "${trigger}"`); | 2395 | console.log(`Image generation mode ${generationTypeKey} triggered with "${trigger}"`); |
| 2395 | 2396 | ||
| 2396 | const quietPrompt = getQuietPrompt(generationType, trigger); | 2397 | const quietPrompt = getQuietPrompt(generationType, trigger); |
| 2397 | const context = getContext(); | 2398 | const context = getContext(); |
| @@ -2428,6 +2429,8 @@ async function generatePicture(initiator, args, trigger, message, callback) { | |||
| 2428 | 2429 | ||
| 2429 | try { | 2430 | try { |
| 2430 | const combineNegatives = (prefix) => { negativePromptPrefix = combinePrefixes(negativePromptPrefix, prefix); }; | 2431 | const combineNegatives = (prefix) => { negativePromptPrefix = combinePrefixes(negativePromptPrefix, prefix); }; |
| 2432 | |||
| 2433 | // generate the text prompt for the image | ||
| 2431 | const prompt = await getPrompt(generationType, message, trigger, quietPrompt, combineNegatives); | 2434 | const prompt = await getPrompt(generationType, message, trigger, quietPrompt, combineNegatives); |
| 2432 | console.log('Processed image prompt:', prompt); | 2435 | console.log('Processed image prompt:', prompt); |
| 2433 | 2436 | ||
| @@ -2438,11 +2441,16 @@ async function generatePicture(initiator, args, trigger, message, callback) { | |||
| 2438 | args._abortController.addEventListener('abort', stopListener); | 2441 | args._abortController.addEventListener('abort', stopListener); |
| 2439 | } | 2442 | } |
| 2440 | 2443 | ||
| 2444 | // generate the image | ||
| 2441 | imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback, initiator, abortController.signal); | 2445 | imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback, initiator, abortController.signal); |
| 2442 | } catch (err) { | 2446 | } catch (err) { |
| 2443 | console.trace(err); | 2447 | console.trace(err); |
| 2444 | toastr.error('SD prompt text generation failed. Reason: ' + err, 'Image Generation'); | 2448 | // errors here are most likely due to text generation failure |
| 2445 | throw new Error('SD prompt text generation failed. Reason: ' + err); | 2449 | // sendGenerationRequest mostly deals with its own errors |
| 2450 | const reason = err.error?.message || err.message || 'Unknown error'; | ||
| 2451 | const errorText = 'SD prompt text generation failed. ' + reason; | ||
| 2452 | toastr.error(errorText, 'Image Generation'); | ||
| 2453 | throw new Error(errorText); | ||
| 2446 | } | 2454 | } |
| 2447 | finally { | 2455 | finally { |
| 2448 | $(stopButton).hide(); | 2456 | $(stopButton).hide(); |
| @@ -2513,7 +2521,7 @@ function restoreOriginalDimensions(savedParams) { | |||
| 2513 | */ | 2521 | */ |
| 2514 | async function getPrompt(generationType, message, trigger, quietPrompt, combineNegatives) { | 2522 | async function getPrompt(generationType, message, trigger, quietPrompt, combineNegatives) { |
| 2515 | let prompt; | 2523 | let prompt; |
| 2516 | 2524 | console.log('getPrompt: Generation mode', generationType, 'triggered with', trigger); | |
| 2517 | switch (generationType) { | 2525 | switch (generationType) { |
| 2518 | case generationMode.RAW_LAST: | 2526 | case generationMode.RAW_LAST: |
| 2519 | prompt = message || getRawLastMessage(); | 2527 | prompt = message || getRawLastMessage(); |
| @@ -2729,7 +2737,7 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP | |||
| 2729 | throw new Error('Endpoint did not return image data.'); | 2737 | throw new Error('Endpoint did not return image data.'); |
| 2730 | } | 2738 | } |
| 2731 | } catch (err) { | 2739 | } catch (err) { |
| 2732 | console.error(err); | 2740 | console.error('Image generation request error: ', err); |
| 2733 | toastr.error('Image generation failed. Please try again.' + '\n\n' + String(err), 'Image Generation'); | 2741 | toastr.error('Image generation failed. Please try again.' + '\n\n' + String(err), 'Image Generation'); |
| 2734 | return; | 2742 | return; |
| 2735 | } | 2743 | } |
| @@ -181,6 +181,14 @@ function setContextSizePreview() { | |||
| 181 | } | 181 | } |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | /** Generates text using the Horde API. | ||
| 185 | * @param {string} prompt | ||
| 186 | * @param params | ||
| 187 | * @param signal | ||
| 188 | * @param reportProgress | ||
| 189 | * @returns {Promise<{text: *, workerName: string}>} | ||
| 190 | * @throws {Error} | ||
| 191 | */ | ||
| 184 | async function generateHorde(prompt, params, signal, reportProgress) { | 192 | async function generateHorde(prompt, params, signal, reportProgress) { |
| 185 | validateHordeModel(); | 193 | validateHordeModel(); |
| 186 | delete params.prompt; | 194 | delete params.prompt; |
| @@ -1313,6 +1313,11 @@ export async function prepareOpenAIMessages({ | |||
| 1313 | return [chat, promptManager.tokenHandler.counts]; | 1313 | return [chat, promptManager.tokenHandler.counts]; |
| 1314 | } | 1314 | } |
| 1315 | 1315 | ||
| 1316 | /** | ||
| 1317 | * Handles errors during streaming requests. | ||
| 1318 | * @param {Response} response | ||
| 1319 | * @param {string} decoded - response text or decoded stream data | ||
| 1320 | */ | ||
| 1316 | function tryParseStreamingError(response, decoded) { | 1321 | function tryParseStreamingError(response, decoded) { |
| 1317 | try { | 1322 | try { |
| 1318 | const data = JSON.parse(decoded); | 1323 | const data = JSON.parse(decoded); |
| @@ -1324,6 +1329,9 @@ function tryParseStreamingError(response, decoded) { | |||
| 1324 | checkQuotaError(data); | 1329 | checkQuotaError(data); |
| 1325 | checkModerationError(data); | 1330 | checkModerationError(data); |
| 1326 | 1331 | ||
| 1332 | // these do not throw correctly (equiv to Error("[object Object]")) | ||
| 1333 | // if trying to fix "[object Object]" displayed to users, start here | ||
| 1334 | |||
| 1327 | if (data.error) { | 1335 | if (data.error) { |
| 1328 | toastr.error(data.error.message || response.statusText, 'Chat Completion API'); | 1336 | toastr.error(data.error.message || response.statusText, 'Chat Completion API'); |
| 1329 | throw new Error(data); | 1337 | throw new Error(data); |
| @@ -1339,15 +1347,22 @@ function tryParseStreamingError(response, decoded) { | |||
| 1339 | } | 1347 | } |
| 1340 | } | 1348 | } |
| 1341 | 1349 | ||
| 1342 | async function checkQuotaError(data) { | 1350 | /** |
| 1343 | const errorText = await renderTemplateAsync('quotaError'); | 1351 | * Checks if the response contains a quota error and displays a popup if it does. |
| 1344 | 1352 | * @param data | |
| 1353 | * @returns {void} | ||
| 1354 | * @throws {object} - response JSON | ||
| 1355 | */ | ||
| 1356 | function checkQuotaError(data) { | ||
| 1345 | if (!data) { | 1357 | if (!data) { |
| 1346 | return; | 1358 | return; |
| 1347 | } | 1359 | } |
| 1348 | 1360 | ||
| 1349 | if (data.quota_error) { | 1361 | if (data.quota_error) { |
| 1350 | callPopup(errorText, 'text'); | 1362 | renderTemplateAsync('quotaError').then((html) => Popup.show.text('Quota Error', html)); |
| 1363 | |||
| 1364 | // this does not throw correctly (equiv to Error("[object Object]")) | ||
| 1365 | // if trying to fix "[object Object]" displayed to users, start here | ||
| 1351 | throw new Error(data); | 1366 | throw new Error(data); |
| 1352 | } | 1367 | } |
| 1353 | } | 1368 | } |
| @@ -1766,6 +1781,15 @@ async function sendAltScaleRequest(messages, logit_bias, signal, type) { | |||
| 1766 | return data.output; | 1781 | return data.output; |
| 1767 | } | 1782 | } |
| 1768 | 1783 | ||
| 1784 | /** | ||
| 1785 | * Send a chat completion request to backend | ||
| 1786 | * @param {string} type (impersonate, quiet, continue, etc) | ||
| 1787 | * @param {Array} messages | ||
| 1788 | * @param {AbortSignal?} signal | ||
| 1789 | * @returns {Promise<unknown>} | ||
| 1790 | * @throws {Error} | ||
| 1791 | */ | ||
| 1792 | |||
| 1769 | async function sendOpenAIRequest(type, messages, signal) { | 1793 | async function sendOpenAIRequest(type, messages, signal) { |
| 1770 | // Provide default abort signal | 1794 | // Provide default abort signal |
| 1771 | if (!signal) { | 1795 | if (!signal) { |
| @@ -2028,12 +2052,13 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2028 | else { | 2052 | else { |
| 2029 | const data = await response.json(); | 2053 | const data = await response.json(); |
| 2030 | 2054 | ||
| 2031 | await checkQuotaError(data); | 2055 | checkQuotaError(data); |
| 2032 | checkModerationError(data); | 2056 | checkModerationError(data); |
| 2033 | 2057 | ||
| 2034 | if (data.error) { | 2058 | if (data.error) { |
| 2035 | toastr.error(data.error.message || response.statusText, t`API returned an error`); | 2059 | const message = data.error.message || response.statusText || t`Unknown error`; |
| 2036 | throw new Error(data); | 2060 | toastr.error(message, t`API returned an error`); |
| 2061 | throw new Error(message); | ||
| 2037 | } | 2062 | } |
| 2038 | 2063 | ||
| 2039 | if (type !== 'quiet') { | 2064 | if (type !== 'quiet') { |
| @@ -1,5 +1,4 @@ | |||
| 1 | import { escapeRegex } from '../utils.js'; | 1 | import { escapeRegex } from '../utils.js'; |
| 2 | import { SlashCommand } from './SlashCommand.js'; | ||
| 3 | import { SlashCommandParser } from './SlashCommandParser.js'; | 2 | import { SlashCommandParser } from './SlashCommandParser.js'; |
| 4 | 3 | ||
| 5 | export class SlashCommandBrowser { | 4 | export class SlashCommandBrowser { |
| @@ -30,7 +29,7 @@ export class SlashCommandBrowser { | |||
| 30 | this.details?.remove(); | 29 | this.details?.remove(); |
| 31 | this.details = null; | 30 | this.details = null; |
| 32 | let query = inp.value.trim(); | 31 | let query = inp.value.trim(); |
| 33 | if (query.slice(-1) == '"' && !/(?:^|\s+)"/.test(query)) { | 32 | if (query.slice(-1) === '"' && !/(?:^|\s+)"/.test(query)) { |
| 34 | query = `"${query}`; | 33 | query = `"${query}`; |
| 35 | } | 34 | } |
| 36 | let fuzzyList = []; | 35 | let fuzzyList = []; |
| @@ -59,7 +58,7 @@ export class SlashCommandBrowser { | |||
| 59 | cmd.helpString, | 58 | cmd.helpString, |
| 60 | ]; | 59 | ]; |
| 61 | const find = ()=>targets.find(t=>(fuzzyList.find(f=>f.test(t)) ?? quotedList.find(q=>t.includes(q))) !== undefined) !== undefined; | 60 | const find = ()=>targets.find(t=>(fuzzyList.find(f=>f.test(t)) ?? quotedList.find(q=>t.includes(q))) !== undefined) !== undefined; |
| 62 | if (fuzzyList.length + quotedList.length == 0 || find()) { | 61 | if (fuzzyList.length + quotedList.length === 0 || find()) { |
| 63 | this.itemMap[cmd.name].classList.remove('isFiltered'); | 62 | this.itemMap[cmd.name].classList.remove('isFiltered'); |
| 64 | } else { | 63 | } else { |
| 65 | this.itemMap[cmd.name].classList.add('isFiltered'); | 64 | this.itemMap[cmd.name].classList.add('isFiltered'); |
| @@ -78,7 +77,7 @@ export class SlashCommandBrowser { | |||
| 78 | list.classList.add('autoComplete'); | 77 | list.classList.add('autoComplete'); |
| 79 | this.cmdList = Object | 78 | this.cmdList = Object |
| 80 | .keys(SlashCommandParser.commands) | 79 | .keys(SlashCommandParser.commands) |
| 81 | .filter(key => SlashCommandParser.commands[key].name == key) // exclude aliases | 80 | .filter(key => SlashCommandParser.commands[key].name === key) // exclude aliases |
| 82 | .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())) | 81 | .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())) |
| 83 | .map(key => SlashCommandParser.commands[key]) | 82 | .map(key => SlashCommandParser.commands[key]) |
| 84 | ; | 83 | ; |
| @@ -97,7 +96,7 @@ export class SlashCommandBrowser { | |||
| 97 | } | 96 | } |
| 98 | } | 97 | } |
| 99 | } | 98 | } |
| 100 | if (this.details != details) { | 99 | if (this.details !== details) { |
| 101 | Array.from(list.querySelectorAll('.selected')).forEach(it=>it.classList.remove('selected')); | 100 | Array.from(list.querySelectorAll('.selected')).forEach(it=>it.classList.remove('selected')); |
| 102 | item.classList.add('selected'); | 101 | item.classList.add('selected'); |
| 103 | this.details?.remove(); | 102 | this.details?.remove(); |
| @@ -124,7 +123,7 @@ export class SlashCommandBrowser { | |||
| 124 | parent.append(this.dom); | 123 | parent.append(this.dom); |
| 125 | 124 | ||
| 126 | this.mo = new MutationObserver(muts=>{ | 125 | this.mo = new MutationObserver(muts=>{ |
| 127 | if (muts.find(mut=>Array.from(mut.removedNodes).find(it=>it == this.dom || it.contains(this.dom)))) { | 126 | if (muts.find(mut=>Array.from(mut.removedNodes).find(it=>it === this.dom || it.contains(this.dom)))) { |
| 128 | this.mo.disconnect(); | 127 | this.mo.disconnect(); |
| 129 | window.removeEventListener('keydown', boundHandler); | 128 | window.removeEventListener('keydown', boundHandler); |
| 130 | } | 129 | } |
| @@ -136,7 +135,7 @@ export class SlashCommandBrowser { | |||
| 136 | } | 135 | } |
| 137 | 136 | ||
| 138 | handleKeyDown(evt) { | 137 | handleKeyDown(evt) { |
| 139 | if (!evt.shiftKey && !evt.altKey && evt.ctrlKey && evt.key.toLowerCase() == 'f') { | 138 | if (!evt.shiftKey && !evt.altKey && evt.ctrlKey && evt.key.toLowerCase() === 'f') { |
| 140 | if (!this.dom.closest('body')) return; | 139 | if (!this.dom.closest('body')) return; |
| 141 | if (this.dom.closest('.mes') && !this.dom.closest('.last_mes')) return; | 140 | if (this.dom.closest('.mes') && !this.dom.closest('.last_mes')) return; |
| 142 | evt.preventDefault(); | 141 | evt.preventDefault(); |
| @@ -880,6 +880,13 @@ function setSettingByName(setting, value, trigger) { | |||
| 880 | } | 880 | } |
| 881 | } | 881 | } |
| 882 | 882 | ||
| 883 | /** | ||
| 884 | * Sends a streaming request for textgenerationwebui. | ||
| 885 | * @param generate_data | ||
| 886 | * @param signal | ||
| 887 | * @returns {Promise<(function(): AsyncGenerator<{swipes: [], text: string, toolCalls: [], logprobs: {token: string, topLogprobs: Candidate[]}|null}, void, *>)|*>} | ||
| 888 | * @throws {Error} - If the response status is not OK, or from within the generator | ||
| 889 | */ | ||
| 883 | async function generateTextGenWithStreaming(generate_data, signal) { | 890 | async function generateTextGenWithStreaming(generate_data, signal) { |
| 884 | generate_data.stream = true; | 891 | generate_data.stream = true; |
| 885 | 892 | ||
| @@ -995,6 +1002,7 @@ export function parseTabbyLogprobs(data) { | |||
| 995 | * @param {Response} response - Response from the server. | 1002 | * @param {Response} response - Response from the server. |
| 996 | * @param {string} decoded - Decoded response body. | 1003 | * @param {string} decoded - Decoded response body. |
| 997 | * @returns {void} Nothing. | 1004 | * @returns {void} Nothing. |
| 1005 | * @throws {Error} If the response contains an error message, throws Error with the message. | ||
| 998 | */ | 1006 | */ |
| 999 | function tryParseStreamingError(response, decoded) { | 1007 | function tryParseStreamingError(response, decoded) { |
| 1000 | let data = {}; | 1008 | let data = {}; |
| @@ -1051,8 +1051,12 @@ router.post('/generate', jsonParser, function (request, response) { | |||
| 1051 | } | 1051 | } |
| 1052 | } catch (error) { | 1052 | } catch (error) { |
| 1053 | console.log('Generation failed', error); | 1053 | console.log('Generation failed', error); |
| 1054 | const message = error.code === 'ECONNREFUSED' | ||
| 1055 | ? `Connection refused: ${error.message}` | ||
| 1056 | : error.message || 'Unknown error occurred'; | ||
| 1057 | |||
| 1054 | if (!response.headersSent) { | 1058 | if (!response.headersSent) { |
| 1055 | response.send({ error: true }); | 1059 | response.status(502).send({ error: { message, ...error } }); |
| 1056 | } else { | 1060 | } else { |
| 1057 | response.end(); | 1061 | response.end(); |
| 1058 | } | 1062 | } |
| @@ -1068,7 +1072,7 @@ router.post('/generate', jsonParser, function (request, response) { | |||
| 1068 | 1072 | ||
| 1069 | const message = errorResponse.statusText || 'Unknown error occurred'; | 1073 | const message = errorResponse.statusText || 'Unknown error occurred'; |
| 1070 | const quota_error = errorResponse.status === 429 && errorData?.error?.type === 'insufficient_quota'; | 1074 | const quota_error = errorResponse.status === 429 && errorData?.error?.type === 'insufficient_quota'; |
| 1071 | console.log(message, responseText); | 1075 | console.log('Chat completion request error: ', message, responseText); |
| 1072 | 1076 | ||
| 1073 | if (!response.headersSent) { | 1077 | if (!response.headersSent) { |
| 1074 | response.send({ error: { message }, quota_error: quota_error }); | 1078 | response.send({ error: { message }, quota_error: quota_error }); |