Stable Diffusion: dedicated LLM connection profile for image prompt generation Reviewed-by: auto-review
| @@ -44,7 +44,7 @@ import { | ||
| 44 | 44 | import { getMessageTimeStamp, humanizedDateTime } from '../../RossAscends-mods.js'; |
| 45 | 45 | import { SECRET_KEYS, secret_state } from '../../secrets.js'; |
| 46 | 46 | import { getNovelAnlas, getNovelUnlimitedImageGeneration, loadNovelSubscriptionData } from '../../nai-settings.js'; |
| 47 | 47 | import { ConnectionManagerRequestService, getMultimodalCaption } from '../shared.js'; |
| 48 | 48 | import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js'; |
| 49 | 49 | import { SlashCommand } from '../../slash-commands/SlashCommand.js'; |
| 50 | 50 | import { |
| @@ -365,6 +365,9 @@ const defaultSettings = { | ||
| 365 | 365 | settings_preset_primary: null, |
| 366 | 366 | settings_preset_secondary: null, |
| 367 | 367 | settings_fallback_enabled: false, |
| 368 | + | |
| 369 | + // Dedicated LLM connection profile for image-prompt generation ('' = use active model) | |
| 370 | + prompt_generation_profile: '', | |
| 368 | 371 | }; |
| 369 | 372 | |
| 370 | 373 | /** |
| @@ -534,6 +537,34 @@ function toggleSourceControls() { | ||
| 534 | 537 | }); |
| 535 | 538 | } |
| 536 | 539 | |
| 540 | +let promptGenerationProfileDropdownInitialized = false; | |
| 541 | + | |
| 542 | +/** | |
| 543 | + * Populates the dedicated prompt-generation connection profile dropdown. | |
| 544 | + * Only initializes once to avoid attaching duplicate Connection Manager event listeners | |
| 545 | + * when loadSettings() is called again (e.g. after loading a settings preset). | |
| 546 | + */ | |
| 547 | +function initPromptGenerationProfileDropdown() { | |
| 548 | + if (promptGenerationProfileDropdownInitialized) { | |
| 549 | + return; | |
| 550 | + } | |
| 551 | + | |
| 552 | + try { | |
| 553 | + ConnectionManagerRequestService.handleDropdown( | |
| 554 | + '#sd_prompt_generation_profile', | |
| 555 | + extension_settings.sd.prompt_generation_profile, | |
| 556 | + (profile) => { | |
| 557 | + extension_settings.sd.prompt_generation_profile = profile?.id ?? ''; | |
| 558 | + saveSettingsDebounced(); | |
| 559 | + }, | |
| 560 | + ); | |
| 561 | + promptGenerationProfileDropdownInitialized = true; | |
| 562 | + } catch (error) { | |
| 563 | + // Connection Manager may be unavailable/disabled; leave the dropdown empty in that case. | |
| 564 | + console.warn('SD: could not populate prompt-generation profile dropdown', error); | |
| 565 | + } | |
| 566 | +} | |
| 567 | + | |
| 537 | 568 | async function loadSettings() { |
| 538 | 569 | // Initialize settings |
| 539 | 570 | if (Object.keys(extension_settings.sd).length === 0) { |
| @@ -661,6 +692,8 @@ async function loadSettings() { | ||
| 661 | 692 | const resolutionId = getClosestKnownResolution(); |
| 662 | 693 | $('#sd_resolution').val(resolutionId); |
| 663 | 694 | |
| 695 | + initPromptGenerationProfileDropdown(); | |
| 696 | + | |
| 664 | 697 | toggleSourceControls(); |
| 665 | 698 | addPromptTemplates(); |
| 666 | 699 | registerFunctionTool(); |
| @@ -3421,7 +3454,24 @@ function getUserAvatarUrl() { | ||
| 3421 | 3454 | */ |
| 3422 | 3455 | async function generatePrompt(quietPrompt) { |
| 3423 | 3456 | const toast = toastr.info('Generating image prompt with an LLM...', 'Image Generation'); |
| 3424 | - const reply = await generateQuietPrompt({ quietPrompt }); | |
| 3457 | + let reply; | |
| 3458 | + const profileId = extension_settings.sd.prompt_generation_profile; | |
| 3459 | + | |
| 3460 | + if (profileId) { | |
| 3461 | + try { | |
| 3462 | + // Use the chosen Connection Manager profile (non-streaming) regardless of the active model. | |
| 3463 | + // 1024 tokens is a sensible default cap for an image-prompt description. | |
| 3464 | + const data = await ConnectionManagerRequestService.sendRequest(profileId, quietPrompt, 1024); | |
| 3465 | + // Non-streaming requests resolve to ExtractedData ({ content, reasoning }); extract the plain text. | |
| 3466 | + reply = typeof data === 'object' && data !== null ? String(data.content ?? '') : ''; | |
| 3467 | + } catch (err) { | |
| 3468 | + console.warn('SD: prompt-generation profile failed, falling back to active model', err); | |
| 3469 | + reply = await generateQuietPrompt({ quietPrompt }); | |
| 3470 | + } | |
| 3471 | + } else { | |
| 3472 | + reply = await generateQuietPrompt({ quietPrompt }); | |
| 3473 | + } | |
| 3474 | + | |
| 3425 | 3475 | const processedReply = processReply(reply); |
| 3426 | 3476 | toastr.clear(toast); |
| 3427 | 3477 | |
| @@ -39,6 +39,9 @@ | ||
| 39 | 39 | <input id="sd_minimal_prompt_processing" type="checkbox" /> |
| 40 | 40 | <span data-i18n="sd_minimal_prompt_processing_txt">Minimal response prompt processing</span> |
| 41 | 41 | </label> |
| 42 | + <label for="sd_prompt_generation_profile" data-i18n="Prompt generation connection profile">Prompt generation connection profile</label> | |
| 43 | + <select id="sd_prompt_generation_profile" class="text_pole"></select> | |
| 44 | + <small data-i18n="sd_prompt_generation_profile_small">Connection profile always used to generate the image prompt text. Leave empty to use the currently active model.</small> | |
| 42 | 45 | <hr> |
| 43 | 46 | <h4 data-i18n="Settings Presets & Fallback">Settings Presets & Fallback</h4> |
| 44 | 47 | <small data-i18n="sd_settings_presets_small">Save the current backend/connection settings (source, model, sampler, dimensions, etc.) as Primary or Secondary presets and load them back later. Prompt templates, styles, and custom entries are not included.</small> |