Linting and commenting Linting and commenting Linting and commenting Linting and commenting Linting and commenting
| @@ -2672,8 +2672,7 @@ export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, q | |||
| 2672 | quietName: quietName, | 2672 | quietName: quietName, |
| 2673 | }; | 2673 | }; |
| 2674 | originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1; | 2674 | originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1; |
| 2675 | const generateFinished = await Generate('quiet', options); | 2675 | return await Generate('quiet', options); |
| 2676 | return generateFinished; | ||
| 2677 | } finally { | 2676 | } finally { |
| 2678 | if (responseLengthCustomized) { | 2677 | if (responseLengthCustomized) { |
| 2679 | restoreResponseLength(main_api, originalResponseLength); | 2678 | restoreResponseLength(main_api, originalResponseLength); |
| @@ -3328,9 +3327,9 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | |||
| 3328 | 3327 | ||
| 3329 | let data = {}; | 3328 | let data = {}; |
| 3330 | 3329 | ||
| 3331 | if (api == 'koboldhorde') { | 3330 | if (api === 'koboldhorde') { |
| 3332 | data = await generateHorde(prompt, generateData, abortController.signal, false); | 3331 | data = await generateHorde(prompt, generateData, abortController.signal, false); |
| 3333 | } else if (api == 'openai') { | 3332 | } else if (api === 'openai') { |
| 3334 | data = await sendOpenAIRequest('quiet', generateData, abortController.signal); | 3333 | data = await sendOpenAIRequest('quiet', generateData, abortController.signal); |
| 3335 | } else { | 3334 | } else { |
| 3336 | const generateUrl = getGenerateUrl(api); | 3335 | const generateUrl = getGenerateUrl(api); |
| @@ -3343,13 +3342,15 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | |||
| 3343 | }); | 3342 | }); |
| 3344 | 3343 | ||
| 3345 | if (!response.ok) { | 3344 | if (!response.ok) { |
| 3346 | const error = await response.json(); | 3345 | throw await response.json(); |
| 3347 | throw error; | ||
| 3348 | } | 3346 | } |
| 3349 | 3347 | ||
| 3350 | data = await response.json(); | 3348 | data = await response.json(); |
| 3351 | } | 3349 | } |
| 3352 | 3350 | ||
| 3351 | // should only happen for text completions | ||
| 3352 | // other frontend paths do not return data if calling the backend fails, | ||
| 3353 | // they throw things instead | ||
| 3353 | if (data.error) { | 3354 | if (data.error) { |
| 3354 | throw new Error(data.response); | 3355 | throw new Error(data.response); |
| 3355 | } | 3356 | } |
| @@ -4401,6 +4402,11 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4401 | return Promise.resolve(); | 4402 | return Promise.resolve(); |
| 4402 | } | 4403 | } |
| 4403 | 4404 | ||
| 4405 | /** | ||
| 4406 | * Saves itemized prompt bits and calls streaming or non-streaming generation API. | ||
| 4407 | * @returns {Promise<void|*|Awaited<*>|String|{fromStream}|string|undefined|Object>} | ||
| 4408 | * @throws {Error|object} Error with message text, or Error with response JSON (OAI/Horde), or the actual response JSON (novel|textgenerationwebui|kobold) | ||
| 4409 | */ | ||
| 4404 | async function finishGenerating() { | 4410 | async function finishGenerating() { |
| 4405 | if (power_user.console_log_prompts) { | 4411 | if (power_user.console_log_prompts) { |
| 4406 | console.log(generate_data.prompt); | 4412 | console.log(generate_data.prompt); |
| @@ -4512,6 +4518,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4512 | 4518 | ||
| 4513 | return finishGenerating().then(onSuccess, onError); | 4519 | return finishGenerating().then(onSuccess, onError); |
| 4514 | 4520 | ||
| 4521 | /** | ||
| 4522 | * Handles the successful response from the generation API. | ||
| 4523 | * @param data | ||
| 4524 | * @returns {Promise<String|{fromStream}|*|string|string|void|Awaited<*>|undefined>} | ||
| 4525 | * @throws {Error} Throws an error if the response data contains an error message | ||
| 4526 | */ | ||
| 4515 | async function onSuccess(data) { | 4527 | async function onSuccess(data) { |
| 4516 | if (!data) return; | 4528 | if (!data) return; |
| 4517 | 4529 | ||
| @@ -4521,6 +4533,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4521 | 4533 | ||
| 4522 | let messageChunk = ''; | 4534 | let messageChunk = ''; |
| 4523 | 4535 | ||
| 4536 | // if an error was returned in data (textgenwebui), show it and throw it | ||
| 4524 | if (data.error) { | 4537 | if (data.error) { |
| 4525 | unblockGeneration(type); | 4538 | unblockGeneration(type); |
| 4526 | generatedPromptCache = ''; | 4539 | generatedPromptCache = ''; |
| @@ -4635,9 +4648,15 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4635 | return Object.defineProperty(new String(getMessage), 'messageChunk', { value: messageChunk }); | 4648 | return Object.defineProperty(new String(getMessage), 'messageChunk', { value: messageChunk }); |
| 4636 | } | 4649 | } |
| 4637 | 4650 | ||
| 4651 | /** | ||
| 4652 | * Exception handler for finishGenerating | ||
| 4653 | * @param {Error|object} exception Error or response JSON | ||
| 4654 | * @throws {Error|object} Re-throws the exception | ||
| 4655 | */ | ||
| 4638 | function onError(exception) { | 4656 | function onError(exception) { |
| 4657 | // if the response JSON was thrown (novel|textgenerationwebui|kobold), show the error message | ||
| 4639 | if (typeof exception?.error?.message === 'string') { | 4658 | if (typeof exception?.error?.message === 'string') { |
| 4640 | toastr.error(exception.error.message, t`Error`, { timeOut: 10000, extendedTimeOut: 20000 }); | 4659 | toastr.error(exception.error.message, t`Text generation error`, { timeOut: 10000, extendedTimeOut: 20000 }); |
| 4641 | } | 4660 | } |
| 4642 | 4661 | ||
| 4643 | generatedPromptCache = ''; | 4662 | generatedPromptCache = ''; |
| @@ -5305,6 +5324,7 @@ function setInContextMessages(lastmsg, type) { | |||
| 5305 | * @param {string} type Generation type | 5324 | * @param {string} type Generation type |
| 5306 | * @param {object} data Generation data | 5325 | * @param {object} data Generation data |
| 5307 | * @returns {Promise<object>} Response data from the API | 5326 | * @returns {Promise<object>} Response data from the API |
| 5327 | * @throws {Error|object} | ||
| 5308 | */ | 5328 | */ |
| 5309 | export async function sendGenerationRequest(type, data) { | 5329 | export async function sendGenerationRequest(type, data) { |
| 5310 | if (main_api === 'openai') { | 5330 | if (main_api === 'openai') { |
| @@ -5324,12 +5344,10 @@ export async function sendGenerationRequest(type, data) { | |||
| 5324 | }); | 5344 | }); |
| 5325 | 5345 | ||
| 5326 | if (!response.ok) { | 5346 | if (!response.ok) { |
| 5327 | const error = await response.json(); | 5347 | throw await response.json(); |
| 5328 | throw error; | ||
| 5329 | } | 5348 | } |
| 5330 | 5349 | ||
| 5331 | const responseData = await response.json(); | 5350 | return await response.json(); |
| 5332 | return responseData; | ||
| 5333 | } | 5351 | } |
| 5334 | 5352 | ||
| 5335 | /** | 5353 | /** |
| @@ -5361,6 +5379,7 @@ export async function sendStreamingRequest(type, data) { | |||
| 5361 | * Gets the generation endpoint URL for the specified API. | 5379 | * Gets the generation endpoint URL for the specified API. |
| 5362 | * @param {string} api API name | 5380 | * @param {string} api API name |
| 5363 | * @returns {string} Generation URL | 5381 | * @returns {string} Generation URL |
| 5382 | * @throws {Error} If the API is unknown | ||
| 5364 | */ | 5383 | */ |
| 5365 | function getGenerateUrl(api) { | 5384 | function getGenerateUrl(api) { |
| 5366 | switch (api) { | 5385 | switch (api) { |
| @@ -2362,6 +2362,7 @@ function ensureSelectionExists(setting, selector) { | |||
| 2362 | * @param {string} [message] Chat message | 2362 | * @param {string} [message] Chat message |
| 2363 | * @param {function} [callback] Callback function | 2363 | * @param {function} [callback] Callback function |
| 2364 | * @returns {Promise<string>} Image path | 2364 | * @returns {Promise<string>} Image path |
| 2365 | * @throws {Error} If the prompt or image generation fails | ||
| 2365 | */ | 2366 | */ |
| 2366 | async function generatePicture(initiator, args, trigger, message, callback) { | 2367 | async function generatePicture(initiator, args, trigger, message, callback) { |
| 2367 | if (!trigger || trigger.trim().length === 0) { | 2368 | if (!trigger || trigger.trim().length === 0) { |
| @@ -2379,7 +2380,7 @@ async function generatePicture(initiator, args, trigger, message, callback) { | |||
| 2379 | 2380 | ||
| 2380 | trigger = trigger.trim(); | 2381 | trigger = trigger.trim(); |
| 2381 | const generationType = getGenerationType(trigger); | 2382 | const generationType = getGenerationType(trigger); |
| 2382 | console.log('Generation mode', generationType, 'triggered with', trigger); | 2383 | console.log('Image generation mode', generationType, 'triggered with', trigger); |
| 2383 | const quietPrompt = getQuietPrompt(generationType, trigger); | 2384 | const quietPrompt = getQuietPrompt(generationType, trigger); |
| 2384 | const context = getContext(); | 2385 | const context = getContext(); |
| 2385 | 2386 | ||
| @@ -2387,7 +2388,7 @@ async function generatePicture(initiator, args, trigger, message, callback) { | |||
| 2387 | ? context.groups[Object.keys(context.groups).filter(x => context.groups[x].id === context.groupId)[0]]?.id?.toString() | 2388 | ? context.groups[Object.keys(context.groups).filter(x => context.groups[x].id === context.groupId)[0]]?.id?.toString() |
| 2388 | : context.characters[context.characterId]?.name; | 2389 | : context.characters[context.characterId]?.name; |
| 2389 | 2390 | ||
| 2390 | if (generationType == generationMode.BACKGROUND) { | 2391 | if (generationType === generationMode.BACKGROUND) { |
| 2391 | const callbackOriginal = callback; | 2392 | const callbackOriginal = callback; |
| 2392 | callback = async function (prompt, imagePath, generationType, _negativePromptPrefix, _initiator, prefixedPrompt) { | 2393 | callback = async function (prompt, imagePath, generationType, _negativePromptPrefix, _initiator, prefixedPrompt) { |
| 2393 | const imgUrl = `url("${encodeURI(imagePath)}")`; | 2394 | const imgUrl = `url("${encodeURI(imagePath)}")`; |
| @@ -2415,6 +2416,8 @@ async function generatePicture(initiator, args, trigger, message, callback) { | |||
| 2415 | 2416 | ||
| 2416 | try { | 2417 | try { |
| 2417 | const combineNegatives = (prefix) => { negativePromptPrefix = combinePrefixes(negativePromptPrefix, prefix); }; | 2418 | const combineNegatives = (prefix) => { negativePromptPrefix = combinePrefixes(negativePromptPrefix, prefix); }; |
| 2419 | |||
| 2420 | // generate the text prompt for the image | ||
| 2418 | const prompt = await getPrompt(generationType, message, trigger, quietPrompt, combineNegatives); | 2421 | const prompt = await getPrompt(generationType, message, trigger, quietPrompt, combineNegatives); |
| 2419 | console.log('Processed image prompt:', prompt); | 2422 | console.log('Processed image prompt:', prompt); |
| 2420 | 2423 | ||
| @@ -2425,6 +2428,7 @@ async function generatePicture(initiator, args, trigger, message, callback) { | |||
| 2425 | args._abortController.addEventListener('abort', stopListener); | 2428 | args._abortController.addEventListener('abort', stopListener); |
| 2426 | } | 2429 | } |
| 2427 | 2430 | ||
| 2431 | // generate the image | ||
| 2428 | imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback, initiator, abortController.signal); | 2432 | imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback, initiator, abortController.signal); |
| 2429 | } catch (err) { | 2433 | } catch (err) { |
| 2430 | console.trace(err); | 2434 | console.trace(err); |
| @@ -2500,7 +2504,7 @@ function restoreOriginalDimensions(savedParams) { | |||
| 2500 | */ | 2504 | */ |
| 2501 | async function getPrompt(generationType, message, trigger, quietPrompt, combineNegatives) { | 2505 | async function getPrompt(generationType, message, trigger, quietPrompt, combineNegatives) { |
| 2502 | let prompt; | 2506 | let prompt; |
| 2503 | 2507 | console.log('getPrompt: Generation mode', generationType, 'triggered with', trigger); | |
| 2504 | switch (generationType) { | 2508 | switch (generationType) { |
| 2505 | case generationMode.RAW_LAST: | 2509 | case generationMode.RAW_LAST: |
| 2506 | prompt = message || getRawLastMessage(); | 2510 | prompt = message || getRawLastMessage(); |
| @@ -2718,7 +2722,7 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP | |||
| 2718 | throw new Error('Endpoint did not return image data.'); | 2722 | throw new Error('Endpoint did not return image data.'); |
| 2719 | } | 2723 | } |
| 2720 | } catch (err) { | 2724 | } catch (err) { |
| 2721 | console.error(err); | 2725 | console.error('Image generation request error: ', err); |
| 2722 | toastr.error('Image generation failed. Please try again.' + '\n\n' + String(err), 'Image Generation'); | 2726 | toastr.error('Image generation failed. Please try again.' + '\n\n' + String(err), 'Image Generation'); |
| 2723 | return; | 2727 | return; |
| 2724 | } | 2728 | } |
| @@ -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; |
| @@ -1312,6 +1312,11 @@ export async function prepareOpenAIMessages({ | |||
| 1312 | return [chat, promptManager.tokenHandler.counts]; | 1312 | return [chat, promptManager.tokenHandler.counts]; |
| 1313 | } | 1313 | } |
| 1314 | 1314 | ||
| 1315 | /** | ||
| 1316 | * Handles errors during streaming requests. | ||
| 1317 | * @param {Response} response | ||
| 1318 | * @param {string} decoded - response text or decoded stream data | ||
| 1319 | */ | ||
| 1315 | function tryParseStreamingError(response, decoded) { | 1320 | function tryParseStreamingError(response, decoded) { |
| 1316 | try { | 1321 | try { |
| 1317 | const data = JSON.parse(decoded); | 1322 | const data = JSON.parse(decoded); |
| @@ -1320,9 +1325,12 @@ function tryParseStreamingError(response, decoded) { | |||
| 1320 | return; | 1325 | return; |
| 1321 | } | 1326 | } |
| 1322 | 1327 | ||
| 1323 | checkQuotaError(data); | 1328 | void checkQuotaError(data); |
| 1324 | checkModerationError(data); | 1329 | checkModerationError(data); |
| 1325 | 1330 | ||
| 1331 | // these do not throw correctly (equiv to Error("[object Object]")) | ||
| 1332 | // if trying to fix "[object Object]" displayed to users, start here | ||
| 1333 | |||
| 1326 | if (data.error) { | 1334 | if (data.error) { |
| 1327 | toastr.error(data.error.message || response.statusText, 'Chat Completion API'); | 1335 | toastr.error(data.error.message || response.statusText, 'Chat Completion API'); |
| 1328 | throw new Error(data); | 1336 | throw new Error(data); |
| @@ -1338,6 +1346,12 @@ function tryParseStreamingError(response, decoded) { | |||
| 1338 | } | 1346 | } |
| 1339 | } | 1347 | } |
| 1340 | 1348 | ||
| 1349 | /** | ||
| 1350 | * Checks if the response contains a quota error and displays a popup if it does. | ||
| 1351 | * @param data | ||
| 1352 | * @returns {Promise<void>} | ||
| 1353 | * @throws {object} - response JSON | ||
| 1354 | */ | ||
| 1341 | async function checkQuotaError(data) { | 1355 | async function checkQuotaError(data) { |
| 1342 | const errorText = await renderTemplateAsync('quotaError'); | 1356 | const errorText = await renderTemplateAsync('quotaError'); |
| 1343 | 1357 | ||
| @@ -1347,6 +1361,9 @@ async function checkQuotaError(data) { | |||
| 1347 | 1361 | ||
| 1348 | if (data.quota_error) { | 1362 | if (data.quota_error) { |
| 1349 | callPopup(errorText, 'text'); | 1363 | callPopup(errorText, 'text'); |
| 1364 | |||
| 1365 | // this does not throw correctly (equiv to Error("[object Object]")) | ||
| 1366 | // if trying to fix "[object Object]" displayed to users, start here | ||
| 1350 | throw new Error(data); | 1367 | throw new Error(data); |
| 1351 | } | 1368 | } |
| 1352 | } | 1369 | } |
| @@ -1765,6 +1782,15 @@ async function sendAltScaleRequest(messages, logit_bias, signal, type) { | |||
| 1765 | return data.output; | 1782 | return data.output; |
| 1766 | } | 1783 | } |
| 1767 | 1784 | ||
| 1785 | /** | ||
| 1786 | * Send a chat completion request to backend | ||
| 1787 | * @param {string} type (impersonate, quiet, continue, etc) | ||
| 1788 | * @param {Array} messages | ||
| 1789 | * @param {AbortSignal?} signal | ||
| 1790 | * @returns {Promise<unknown>} | ||
| 1791 | * @throws {Error} | ||
| 1792 | */ | ||
| 1793 | |||
| 1768 | async function sendOpenAIRequest(type, messages, signal) { | 1794 | async function sendOpenAIRequest(type, messages, signal) { |
| 1769 | // Provide default abort signal | 1795 | // Provide default abort signal |
| 1770 | if (!signal) { | 1796 | if (!signal) { |
| @@ -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 = {}; |