Add a function tool for image generation
| @@ -32,6 +32,7 @@ import { debounce_timeout } from '../../constants.js'; | |||
| 32 | import { SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js'; | 32 | import { SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js'; |
| 33 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from '../../popup.js'; | 33 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from '../../popup.js'; |
| 34 | import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; | 34 | import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 35 | import { ToolManager } from '../../tool-calling.js'; | ||
| 35 | export { MODULE_NAME }; | 36 | export { MODULE_NAME }; |
| 36 | 37 | ||
| 37 | const MODULE_NAME = 'sd'; | 38 | const MODULE_NAME = 'sd'; |
| @@ -62,6 +63,7 @@ const initiators = { | |||
| 62 | interactive: 'interactive', | 63 | interactive: 'interactive', |
| 63 | wand: 'wand', | 64 | wand: 'wand', |
| 64 | swipe: 'swipe', | 65 | swipe: 'swipe', |
| 66 | tool: 'tool', | ||
| 65 | }; | 67 | }; |
| 66 | 68 | ||
| 67 | const generationMode = { | 69 | const generationMode = { |
| @@ -226,6 +228,7 @@ const defaultSettings = { | |||
| 226 | multimodal_captioning: false, | 228 | multimodal_captioning: false, |
| 227 | snap: false, | 229 | snap: false, |
| 228 | free_extend: false, | 230 | free_extend: false, |
| 231 | function_tool: false, | ||
| 229 | 232 | ||
| 230 | prompts: promptTemplates, | 233 | prompts: promptTemplates, |
| 231 | 234 | ||
| @@ -291,6 +294,10 @@ const defaultSettings = { | |||
| 291 | const writePromptFieldsDebounced = debounce(writePromptFields, debounce_timeout.relaxed); | 294 | const writePromptFieldsDebounced = debounce(writePromptFields, debounce_timeout.relaxed); |
| 292 | 295 | ||
| 293 | function processTriggers(chat, _, abort) { | 296 | function processTriggers(chat, _, abort) { |
| 297 | if (extension_settings.sd.function_tool && ToolManager.isToolCallingSupported()) { | ||
| 298 | return; | ||
| 299 | } | ||
| 300 | |||
| 294 | if (!extension_settings.sd.interactive_mode) { | 301 | if (!extension_settings.sd.interactive_mode) { |
| 295 | return; | 302 | return; |
| 296 | } | 303 | } |
| @@ -447,6 +454,7 @@ async function loadSettings() { | |||
| 447 | $('#sd_interactive_visible').prop('checked', extension_settings.sd.interactive_visible); | 454 | $('#sd_interactive_visible').prop('checked', extension_settings.sd.interactive_visible); |
| 448 | $('#sd_stability_style_preset').val(extension_settings.sd.stability_style_preset); | 455 | $('#sd_stability_style_preset').val(extension_settings.sd.stability_style_preset); |
| 449 | $('#sd_huggingface_model_id').val(extension_settings.sd.huggingface_model_id); | 456 | $('#sd_huggingface_model_id').val(extension_settings.sd.huggingface_model_id); |
| 457 | $('#sd_function_tool').prop('checked', extension_settings.sd.function_tool); | ||
| 450 | 458 | ||
| 451 | for (const style of extension_settings.sd.styles) { | 459 | for (const style of extension_settings.sd.styles) { |
| 452 | const option = document.createElement('option'); | 460 | const option = document.createElement('option'); |
| @@ -461,6 +469,7 @@ async function loadSettings() { | |||
| 461 | 469 | ||
| 462 | toggleSourceControls(); | 470 | toggleSourceControls(); |
| 463 | addPromptTemplates(); | 471 | addPromptTemplates(); |
| 472 | registerFunctionTool(); | ||
| 464 | 473 | ||
| 465 | await loadSettingOptions(); | 474 | await loadSettingOptions(); |
| 466 | } | 475 | } |
| @@ -910,6 +919,12 @@ async function onSourceChange() { | |||
| 910 | await loadSettingOptions(); | 919 | await loadSettingOptions(); |
| 911 | } | 920 | } |
| 912 | 921 | ||
| 922 | function onFunctionToolInput() { | ||
| 923 | extension_settings.sd.function_tool = !!$(this).prop('checked'); | ||
| 924 | saveSettingsDebounced(); | ||
| 925 | registerFunctionTool(); | ||
| 926 | } | ||
| 927 | |||
| 913 | async function onOpenAiStyleSelect() { | 928 | async function onOpenAiStyleSelect() { |
| 914 | extension_settings.sd.openai_style = String($('#sd_openai_style').find(':selected').val()); | 929 | extension_settings.sd.openai_style = String($('#sd_openai_style').find(':selected').val()); |
| 915 | saveSettingsDebounced(); | 930 | saveSettingsDebounced(); |
| @@ -3822,6 +3837,44 @@ function applyCommandArguments(args) { | |||
| 3822 | return currentSettings; | 3837 | return currentSettings; |
| 3823 | } | 3838 | } |
| 3824 | 3839 | ||
| 3840 | function registerFunctionTool() { | ||
| 3841 | if (!extension_settings.sd.function_tool) { | ||
| 3842 | return ToolManager.unregisterFunctionTool('GenerateImage'); | ||
| 3843 | } | ||
| 3844 | |||
| 3845 | ToolManager.registerFunctionTool({ | ||
| 3846 | name: 'GenerateImage', | ||
| 3847 | displayName: 'Generate Image', | ||
| 3848 | description: [ | ||
| 3849 | 'Generate an image from a given text prompt.', | ||
| 3850 | 'Use when a user asks for an image, a selfie, to picture a scene, etc.', | ||
| 3851 | ].join(' '), | ||
| 3852 | parameters: Object.freeze({ | ||
| 3853 | $schema: 'http://json-schema.org/draft-04/schema#', | ||
| 3854 | type: 'object', | ||
| 3855 | properties: { | ||
| 3856 | prompt: { | ||
| 3857 | type: 'string', | ||
| 3858 | description: [ | ||
| 3859 | 'The text prompt used to generate the image.', | ||
| 3860 | 'Must represent an exhaustive description of the desired image that will allow an artist or a photographer to perfectly recreate it.', | ||
| 3861 | ], | ||
| 3862 | }, | ||
| 3863 | }, | ||
| 3864 | required: [ | ||
| 3865 | 'prompt', | ||
| 3866 | ], | ||
| 3867 | }), | ||
| 3868 | action: async (args) => { | ||
| 3869 | if (!isValidState()) throw new Error('Image generation is not configured.'); | ||
| 3870 | if (!args) throw new Error('Missing arguments'); | ||
| 3871 | if (!args.prompt) throw new Error('Missing prompt'); | ||
| 3872 | return generatePicture(initiators.tool, {}, args.prompt); | ||
| 3873 | }, | ||
| 3874 | formatMessage: () => 'Generating an image...', | ||
| 3875 | }); | ||
| 3876 | } | ||
| 3877 | |||
| 3825 | jQuery(async () => { | 3878 | jQuery(async () => { |
| 3826 | await addSDGenButtons(); | 3879 | await addSDGenButtons(); |
| 3827 | 3880 | ||
| @@ -4175,6 +4228,7 @@ jQuery(async () => { | |||
| 4175 | $('#sd_stability_key').on('click', onStabilityKeyClick); | 4228 | $('#sd_stability_key').on('click', onStabilityKeyClick); |
| 4176 | $('#sd_stability_style_preset').on('change', onStabilityStylePresetChange); | 4229 | $('#sd_stability_style_preset').on('change', onStabilityStylePresetChange); |
| 4177 | $('#sd_huggingface_model_id').on('input', onHFModelInput); | 4230 | $('#sd_huggingface_model_id').on('input', onHFModelInput); |
| 4231 | $('#sd_function_tool').on('input', onFunctionToolInput); | ||
| 4178 | 4232 | ||
| 4179 | if (!CSS.supports('field-sizing', 'content')) { | 4233 | if (!CSS.supports('field-sizing', 'content')) { |
| 4180 | $('.sd_settings .inline-drawer-toggle').on('click', function () { | 4234 | $('.sd_settings .inline-drawer-toggle').on('click', function () { |
| @@ -18,6 +18,10 @@ | |||
| 18 | <input id="sd_interactive_mode" type="checkbox" /> | 18 | <input id="sd_interactive_mode" type="checkbox" /> |
| 19 | <span data-i18n="sd_interactive_mode_txt">Interactive mode</span> | 19 | <span data-i18n="sd_interactive_mode_txt">Interactive mode</span> |
| 20 | </label> | 20 | </label> |
| 21 | <label for="sd_function_tool" class="checkbox_label" data-i18n="[title]sd_function_tool" title="Use the function tool to automatically detect intents to generate images."> | ||
| 22 | <input id="sd_function_tool" type="checkbox" /> | ||
| 23 | <span data-i18n="sd_function_tool_txt">Enable function tool</span> | ||
| 24 | </label> | ||
| 21 | <label for="sd_multimodal_captioning" class="checkbox_label" data-i18n="[title]sd_multimodal_captioning" title="Use multimodal captioning to generate prompts for user and character portraits based on their avatars."> | 25 | <label for="sd_multimodal_captioning" class="checkbox_label" data-i18n="[title]sd_multimodal_captioning" title="Use multimodal captioning to generate prompts for user and character portraits based on their avatars."> |
| 22 | <input id="sd_multimodal_captioning" type="checkbox" /> | 26 | <input id="sd_multimodal_captioning" type="checkbox" /> |
| 23 | <span data-i18n="sd_multimodal_captioning_txt">Use multimodal captioning for portraits</span> | 27 | <span data-i18n="sd_multimodal_captioning_txt">Use multimodal captioning for portraits</span> |