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 | 2672 | quietName: quietName, |
| 2673 | 2673 | }; |
| 2674 | 2674 | originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1; |
| 2675 | 2675 | const generateFinished =return await Generate('quiet', options); |
| 2676 | - return generateFinished; | |
| 2677 | 2676 | } finally { |
| 2678 | 2677 | if (responseLengthCustomized) { |
| 2679 | 2678 | restoreResponseLength(main_api, originalResponseLength); |
| @@ -3328,9 +3327,9 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | ||
| 3328 | 3327 | |
| 3329 | 3328 | let data = {}; |
| 3330 | 3329 | |
| 3331 | 3330 | if (api === 'koboldhorde') { |
| 3332 | 3331 | data = await generateHorde(prompt, generateData, abortController.signal, false); |
| 3333 | 3332 | } else if (api === 'openai') { |
| 3334 | 3333 | data = await sendOpenAIRequest('quiet', generateData, abortController.signal); |
| 3335 | 3334 | } else { |
| 3336 | 3335 | const generateUrl = getGenerateUrl(api); |
| @@ -3343,13 +3342,15 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | ||
| 3343 | 3342 | }); |
| 3344 | 3343 | |
| 3345 | 3344 | if (!response.ok) { |
| 3346 | 3345 | const error =throw await response.json(); |
| 3347 | - throw error; | |
| 3348 | 3346 | } |
| 3349 | 3347 | |
| 3350 | 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 | 3354 | if (data.error) { |
| 3354 | 3355 | throw new Error(data.response); |
| 3355 | 3356 | } |
| @@ -4401,6 +4402,11 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4401 | 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 | 4410 | async function finishGenerating() { |
| 4405 | 4411 | if (power_user.console_log_prompts) { |
| 4406 | 4412 | console.log(generate_data.prompt); |
| @@ -4512,6 +4518,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4512 | 4518 | |
| 4513 | 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 | 4527 | async function onSuccess(data) { |
| 4516 | 4528 | if (!data) return; |
| 4517 | 4529 | |
| @@ -4521,6 +4533,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4521 | 4533 | |
| 4522 | 4534 | let messageChunk = ''; |
| 4523 | 4535 | |
| 4536 | + // if an error was returned in data (textgenwebui), show it and throw it | |
| 4524 | 4537 | if (data.error) { |
| 4525 | 4538 | unblockGeneration(type); |
| 4526 | 4539 | generatedPromptCache = ''; |
| @@ -4635,9 +4648,15 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4635 | 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 | 4656 | function onError(exception) { |
| 4657 | + // if the response JSON was thrown (novel|textgenerationwebui|kobold), show the error message | |
| 4639 | 4658 | if (typeof exception?.error?.message === 'string') { |
| 4640 | 4659 | toastr.error(exception.error.message, t`ErrorText generation error`, { timeOut: 10000, extendedTimeOut: 20000 }); |
| 4641 | 4660 | } |
| 4642 | 4661 | |
| 4643 | 4662 | generatedPromptCache = ''; |
| @@ -5305,6 +5324,7 @@ function setInContextMessages(lastmsg, type) { | ||
| 5305 | 5324 | * @param {string} type Generation type |
| 5306 | 5325 | * @param {object} data Generation data |
| 5307 | 5326 | * @returns {Promise<object>} Response data from the API |
| 5327 | + * @throws {Error|object} | |
| 5308 | 5328 | */ |
| 5309 | 5329 | export async function sendGenerationRequest(type, data) { |
| 5310 | 5330 | if (main_api === 'openai') { |
| @@ -5324,12 +5344,10 @@ export async function sendGenerationRequest(type, data) { | ||
| 5324 | 5344 | }); |
| 5325 | 5345 | |
| 5326 | 5346 | if (!response.ok) { |
| 5327 | 5347 | const error =throw await response.json(); |
| 5328 | - throw error; | |
| 5329 | 5348 | } |
| 5330 | 5349 | |
| 5331 | 5350 | const responseData =return await response.json(); |
| 5332 | - return responseData; | |
| 5333 | 5351 | } |
| 5334 | 5352 | |
| 5335 | 5353 | /** |
| @@ -5361,6 +5379,7 @@ export async function sendStreamingRequest(type, data) { | ||
| 5361 | 5379 | * Gets the generation endpoint URL for the specified API. |
| 5362 | 5380 | * @param {string} api API name |
| 5363 | 5381 | * @returns {string} Generation URL |
| 5382 | + * @throws {Error} If the API is unknown | |
| 5364 | 5383 | */ |
| 5365 | 5384 | function getGenerateUrl(api) { |
| 5366 | 5385 | switch (api) { |
| @@ -2362,6 +2362,7 @@ function ensureSelectionExists(setting, selector) { | ||
| 2362 | 2362 | * @param {string} [message] Chat message |
| 2363 | 2363 | * @param {function} [callback] Callback function |
| 2364 | 2364 | * @returns {Promise<string>} Image path |
| 2365 | + * @throws {Error} If the prompt or image generation fails | |
| 2365 | 2366 | */ |
| 2366 | 2367 | async function generatePicture(initiator, args, trigger, message, callback) { |
| 2367 | 2368 | if (!trigger || trigger.trim().length === 0) { |
| @@ -2379,7 +2380,7 @@ async function generatePicture(initiator, args, trigger, message, callback) { | ||
| 2379 | 2380 | |
| 2380 | 2381 | trigger = trigger.trim(); |
| 2381 | 2382 | const generationType = getGenerationType(trigger); |
| 2382 | 2383 | console.log('GenerationImage generation mode', generationType, 'triggered with', trigger); |
| 2383 | 2384 | const quietPrompt = getQuietPrompt(generationType, trigger); |
| 2384 | 2385 | const context = getContext(); |
| 2385 | 2386 | |
| @@ -2387,7 +2388,7 @@ async function generatePicture(initiator, args, trigger, message, callback) { | ||
| 2387 | 2388 | ? context.groups[Object.keys(context.groups).filter(x => context.groups[x].id === context.groupId)[0]]?.id?.toString() |
| 2388 | 2389 | : context.characters[context.characterId]?.name; |
| 2389 | 2390 | |
| 2390 | 2391 | if (generationType === generationMode.BACKGROUND) { |
| 2391 | 2392 | const callbackOriginal = callback; |
| 2392 | 2393 | callback = async function (prompt, imagePath, generationType, _negativePromptPrefix, _initiator, prefixedPrompt) { |
| 2393 | 2394 | const imgUrl = `url("${encodeURI(imagePath)}")`; |
| @@ -2415,6 +2416,8 @@ async function generatePicture(initiator, args, trigger, message, callback) { | ||
| 2415 | 2416 | |
| 2416 | 2417 | try { |
| 2417 | 2418 | const combineNegatives = (prefix) => { negativePromptPrefix = combinePrefixes(negativePromptPrefix, prefix); }; |
| 2419 | + | |
| 2420 | + // generate the text prompt for the image | |
| 2418 | 2421 | const prompt = await getPrompt(generationType, message, trigger, quietPrompt, combineNegatives); |
| 2419 | 2422 | console.log('Processed image prompt:', prompt); |
| 2420 | 2423 | |
| @@ -2425,6 +2428,7 @@ async function generatePicture(initiator, args, trigger, message, callback) { | ||
| 2425 | 2428 | args._abortController.addEventListener('abort', stopListener); |
| 2426 | 2429 | } |
| 2427 | 2430 | |
| 2431 | + // generate the image | |
| 2428 | 2432 | imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback, initiator, abortController.signal); |
| 2429 | 2433 | } catch (err) { |
| 2430 | 2434 | console.trace(err); |
| @@ -2500,7 +2504,7 @@ function restoreOriginalDimensions(savedParams) { | ||
| 2500 | 2504 | */ |
| 2501 | 2505 | async function getPrompt(generationType, message, trigger, quietPrompt, combineNegatives) { |
| 2502 | 2506 | let prompt; |
| 2503 | - | |
| 2507 | + console.log('getPrompt: Generation mode', generationType, 'triggered with', trigger); | |
| 2504 | 2508 | switch (generationType) { |
| 2505 | 2509 | case generationMode.RAW_LAST: |
| 2506 | 2510 | prompt = message || getRawLastMessage(); |
| @@ -2718,7 +2722,7 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP | ||
| 2718 | 2722 | throw new Error('Endpoint did not return image data.'); |
| 2719 | 2723 | } |
| 2720 | 2724 | } catch (err) { |
| 2721 | 2725 | console.error('Image generation request error: ', err); |
| 2722 | 2726 | toastr.error('Image generation failed. Please try again.' + '\n\n' + String(err), 'Image Generation'); |
| 2723 | 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 | 192 | async function generateHorde(prompt, params, signal, reportProgress) { |
| 185 | 193 | validateHordeModel(); |
| 186 | 194 | delete params.prompt; |
| @@ -1312,6 +1312,11 @@ export async function prepareOpenAIMessages({ | ||
| 1312 | 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 | 1320 | function tryParseStreamingError(response, decoded) { |
| 1316 | 1321 | try { |
| 1317 | 1322 | const data = JSON.parse(decoded); |
| @@ -1320,9 +1325,12 @@ function tryParseStreamingError(response, decoded) { | ||
| 1320 | 1325 | return; |
| 1321 | 1326 | } |
| 1322 | 1327 | |
| 1323 | 1328 | void checkQuotaError(data); |
| 1324 | 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 | 1334 | if (data.error) { |
| 1327 | 1335 | toastr.error(data.error.message || response.statusText, 'Chat Completion API'); |
| 1328 | 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 | 1355 | async function checkQuotaError(data) { |
| 1342 | 1356 | const errorText = await renderTemplateAsync('quotaError'); |
| 1343 | 1357 | |
| @@ -1347,6 +1361,9 @@ async function checkQuotaError(data) { | ||
| 1347 | 1361 | |
| 1348 | 1362 | if (data.quota_error) { |
| 1349 | 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 | 1367 | throw new Error(data); |
| 1351 | 1368 | } |
| 1352 | 1369 | } |
| @@ -1765,6 +1782,15 @@ async function sendAltScaleRequest(messages, logit_bias, signal, type) { | ||
| 1765 | 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 | 1794 | async function sendOpenAIRequest(type, messages, signal) { |
| 1769 | 1795 | // Provide default abort signal |
| 1770 | 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 | 890 | async function generateTextGenWithStreaming(generate_data, signal) { |
| 884 | 891 | generate_data.stream = true; |
| 885 | 892 | |
| @@ -995,6 +1002,7 @@ export function parseTabbyLogprobs(data) { | ||
| 995 | 1002 | * @param {Response} response - Response from the server. |
| 996 | 1003 | * @param {string} decoded - Decoded response body. |
| 997 | 1004 | * @returns {void} Nothing. |
| 1005 | + * @throws {Error} If the response contains an error message, throws Error with the message. | |
| 998 | 1006 | */ |
| 999 | 1007 | function tryParseStreamingError(response, decoded) { |
| 1000 | 1008 | let data = {}; |