2023-12-02 19:04:51 +01:00
import { getBase64Async , saveBase64AsFile } from '../../utils.js' ;
import { getContext , getApiUrl , doExtrasFetch , extension _settings , modules } from '../../extensions.js' ;
import { callPopup , getRequestHeaders , saveSettingsDebounced , substituteParams } from '../../../script.js' ;
import { getMessageTimeStamp } from '../../RossAscends-mods.js' ;
import { SECRET _KEYS , secret _state } from '../../secrets.js' ;
import { getMultimodalCaption } from '../shared.js' ;
2023-12-19 23:45:45 +01:00
import { textgen _types , textgenerationwebui _settings } from '../../textgen-settings.js' ;
2023-07-20 19:32:15 +02:00
export { MODULE _NAME } ;
const MODULE _NAME = 'caption' ;
2023-11-07 00:58:34 +01:00
const PROMPT _DEFAULT = 'What’ s in this image?' ;
const TEMPLATE _DEFAULT = '[{{user}} sends {{char}} a picture that contains: {{caption}}]' ;
2023-11-17 22:19:21 +01:00
/ * *
* Migrates old extension settings to the new format .
* Must keep this function for compatibility with old settings .
* /
2023-11-07 00:58:34 +01:00
function migrateSettings ( ) {
2023-11-07 00:28:46 +01:00
if ( extension _settings . caption . local !== undefined ) {
extension _settings . caption . source = extension _settings . caption . local ? 'local' : 'extras' ;
}
delete extension _settings . caption . local ;
2023-11-07 00:58:34 +01:00
if ( ! extension _settings . caption . source ) {
extension _settings . caption . source = 'extras' ;
}
2023-11-17 22:19:21 +01:00
if ( extension _settings . caption . source === 'openai' ) {
extension _settings . caption . source = 'multimodal' ;
extension _settings . caption . multimodal _api = 'openai' ;
extension _settings . caption . multimodal _model = 'gpt-4-vision-preview' ;
}
if ( ! extension _settings . caption . multimodal _api ) {
extension _settings . caption . multimodal _api = 'openai' ;
}
if ( ! extension _settings . caption . multimodal _model ) {
extension _settings . caption . multimodal _model = 'gpt-4-vision-preview' ;
}
2023-11-07 00:58:34 +01:00
if ( ! extension _settings . caption . prompt ) {
extension _settings . caption . prompt = PROMPT _DEFAULT ;
}
if ( ! extension _settings . caption . template ) {
extension _settings . caption . template = TEMPLATE _DEFAULT ;
}
2023-11-07 00:28:46 +01:00
}
2023-11-17 22:19:21 +01:00
/ * *
* Sets an image icon for the send button .
* /
2023-07-20 19:32:15 +02:00
async function setImageIcon ( ) {
try {
const sendButton = $ ( '#send_picture .extensionsMenuExtensionButton' ) ;
sendButton . addClass ( 'fa-image' ) ;
sendButton . removeClass ( 'fa-hourglass-half' ) ;
}
catch ( error ) {
console . log ( error ) ;
}
}
2023-11-17 22:19:21 +01:00
/ * *
* Sets a spinner icon for the send button .
* /
2023-07-20 19:32:15 +02:00
async function setSpinnerIcon ( ) {
try {
const sendButton = $ ( '#send_picture .extensionsMenuExtensionButton' ) ;
sendButton . removeClass ( 'fa-image' ) ;
sendButton . addClass ( 'fa-hourglass-half' ) ;
}
catch ( error ) {
console . log ( error ) ;
}
}
2023-11-17 22:19:21 +01:00
/ * *
* Sends a captioned message to the chat .
* @ param { string } caption Caption text
* @ param { string } image Image URL
* /
2023-07-20 19:32:15 +02:00
async function sendCaptionedMessage ( caption , image ) {
const context = getContext ( ) ;
2023-11-07 00:58:34 +01:00
let template = extension _settings . caption . template || TEMPLATE _DEFAULT ;
if ( ! /{{caption}}/i . test ( template ) ) {
2023-12-02 20:11:06 +01:00
console . warn ( 'Poka-yoke: Caption template does not contain {{caption}}. Appending it.' ) ;
2023-11-07 00:58:34 +01:00
template += ' {{caption}}' ;
}
let messageText = substituteParams ( template ) . replace ( /{{caption}}/i , caption ) ;
2023-07-20 19:32:15 +02:00
if ( extension _settings . caption . refine _mode ) {
messageText = await callPopup (
'<h3>Review and edit the generated message:</h3>Press "Cancel" to abort the caption sending.' ,
'input' ,
messageText ,
{ rows : 5 , okButton : 'Send' } ) ;
if ( ! messageText ) {
throw new Error ( 'User aborted the caption sending.' ) ;
}
}
const message = {
name : context . name1 ,
is _user : true ,
2023-08-22 17:13:03 +02:00
send _date : getMessageTimeStamp ( ) ,
2023-07-20 19:32:15 +02:00
mes : messageText ,
extra : {
image : image ,
title : messageText ,
} ,
} ;
context . chat . push ( message ) ;
context . addOneMessage ( message ) ;
}
2023-11-07 00:28:46 +01:00
/ * *
2023-11-17 22:19:21 +01:00
* Generates a caption for an image using a selected source .
2023-11-07 00:28:46 +01:00
* @ param { string } base64Img Base64 encoded image without the data : image / ... ; base64 , prefix
* @ param { string } fileData Base64 encoded image with the data : image / ... ; base64 , prefix
2023-11-17 22:19:21 +01:00
* @ returns { Promise < { caption : string } > } Generated caption
2023-11-07 00:28:46 +01:00
* /
async function doCaptionRequest ( base64Img , fileData ) {
switch ( extension _settings . caption . source ) {
case 'local' :
return await captionLocal ( base64Img ) ;
case 'extras' :
return await captionExtras ( base64Img ) ;
case 'horde' :
return await captionHorde ( base64Img ) ;
2023-11-17 22:19:21 +01:00
case 'multimodal' :
2023-12-19 23:45:45 +01:00
return await captionMultimodal ( fileData ) ;
2023-11-07 00:28:46 +01:00
default :
throw new Error ( 'Unknown caption source.' ) ;
}
}
2023-07-20 19:32:15 +02:00
2023-11-17 22:19:21 +01:00
/ * *
* Generates a caption for an image using Extras API .
* @ param { string } base64Img Base64 encoded image without the data : image / ... ; base64 , prefix
* @ returns { Promise < { caption : string } > } Generated caption
* /
2023-11-07 00:28:46 +01:00
async function captionExtras ( base64Img ) {
if ( ! modules . includes ( 'caption' ) ) {
throw new Error ( 'No captioning module is available.' ) ;
}
2023-07-20 19:32:15 +02:00
2023-11-07 00:28:46 +01:00
const url = new URL ( getApiUrl ( ) ) ;
url . pathname = '/api/caption' ;
2023-07-20 19:32:15 +02:00
2023-11-07 00:28:46 +01:00
const apiResult = await doExtrasFetch ( url , {
method : 'POST' ,
headers : {
'Content-Type' : 'application/json' ,
'Bypass-Tunnel-Reminder' : 'bypass' ,
} ,
2023-12-02 21:06:57 +01:00
body : JSON . stringify ( { image : base64Img } ) ,
2023-11-07 00:28:46 +01:00
} ) ;
2023-09-11 23:15:21 +02:00
2023-11-07 00:28:46 +01:00
if ( ! apiResult . ok ) {
throw new Error ( 'Failed to caption image via Extras.' ) ;
}
const data = await apiResult . json ( ) ;
return data ;
}
2023-11-17 22:19:21 +01:00
/ * *
* Generates a caption for an image using a local model .
* @ param { string } base64Img Base64 encoded image without the data : image / ... ; base64 , prefix
* @ returns { Promise < { caption : string } > } Generated caption
* /
2023-11-07 00:28:46 +01:00
async function captionLocal ( base64Img ) {
const apiResult = await fetch ( '/api/extra/caption' , {
method : 'POST' ,
headers : getRequestHeaders ( ) ,
2023-12-02 21:06:57 +01:00
body : JSON . stringify ( { image : base64Img } ) ,
2023-11-07 00:28:46 +01:00
} ) ;
if ( ! apiResult . ok ) {
throw new Error ( 'Failed to caption image via local pipeline.' ) ;
}
const data = await apiResult . json ( ) ;
return data ;
}
2023-11-17 22:19:21 +01:00
/ * *
* Generates a caption for an image using a Horde model .
* @ param { string } base64Img Base64 encoded image without the data : image / ... ; base64 , prefix
* @ returns { Promise < { caption : string } > } Generated caption
* /
2023-11-07 00:28:46 +01:00
async function captionHorde ( base64Img ) {
const apiResult = await fetch ( '/api/horde/caption-image' , {
method : 'POST' ,
headers : getRequestHeaders ( ) ,
2023-12-02 21:06:57 +01:00
body : JSON . stringify ( { image : base64Img } ) ,
2023-11-07 00:28:46 +01:00
} ) ;
if ( ! apiResult . ok ) {
throw new Error ( 'Failed to caption image via Horde.' ) ;
2023-09-11 23:15:21 +02:00
}
2023-11-07 00:28:46 +01:00
const data = await apiResult . json ( ) ;
return data ;
}
2023-11-17 22:19:21 +01:00
/ * *
* Generates a caption for an image using a multimodal model .
* @ param { string } base64Img Base64 encoded image with the data : image / ... ; base64 , prefix
* @ returns { Promise < { caption : string } > } Generated caption
* /
async function captionMultimodal ( base64Img ) {
2023-12-20 20:23:59 +01:00
let prompt = extension _settings . caption . prompt || PROMPT _DEFAULT ;
if ( extension _settings . caption . prompt _ask ) {
const customPrompt = await callPopup ( '<h3>Enter a comment or question:</h3>' , 'input' , prompt , { rows : 2 } ) ;
if ( ! customPrompt ) {
throw new Error ( 'User aborted the caption sending.' ) ;
}
prompt = String ( customPrompt ) . trim ( ) ;
}
2023-11-17 22:19:21 +01:00
const caption = await getMultimodalCaption ( base64Img , prompt ) ;
return { caption } ;
2023-09-11 23:15:21 +02:00
}
async function onSelectImage ( e ) {
setSpinnerIcon ( ) ;
const file = e . target . files [ 0 ] ;
if ( ! file || ! ( file instanceof File ) ) {
return ;
}
try {
const context = getContext ( ) ;
const fileData = await getBase64Async ( file ) ;
const base64Format = fileData . split ( ',' ) [ 0 ] . split ( ';' ) [ 0 ] . split ( '/' ) [ 1 ] ;
const base64Data = fileData . split ( ',' ) [ 1 ] ;
2023-11-17 22:19:21 +01:00
const { caption } = await doCaptionRequest ( base64Data , fileData ) ;
const imagePath = await saveBase64AsFile ( base64Data , context . name2 , '' , base64Format ) ;
2023-09-11 23:15:21 +02:00
await sendCaptionedMessage ( caption , imagePath ) ;
2023-07-20 19:32:15 +02:00
}
catch ( error ) {
2023-09-11 23:15:21 +02:00
toastr . error ( 'Failed to caption image.' ) ;
2023-07-20 19:32:15 +02:00
console . log ( error ) ;
}
finally {
e . target . form . reset ( ) ;
setImageIcon ( ) ;
}
}
function onRefineModeInput ( ) {
extension _settings . caption . refine _mode = $ ( '#caption_refine_mode' ) . prop ( 'checked' ) ;
saveSettingsDebounced ( ) ;
}
jQuery ( function ( ) {
function addSendPictureButton ( ) {
const sendButton = $ ( `
< div id = "send_picture" class = "list-group-item flex-container flexGap5" >
< div class = "fa-solid fa-image extensionsMenuExtensionButton" > < / d i v >
2023-11-18 18:23:58 +01:00
Generate Caption
< / d i v > ` ) ;
const attachFileButton = $ ( `
< div id = "attachFile" class = "list-group-item flex-container flexGap5" >
< div class = "fa-solid fa-paperclip extensionsMenuExtensionButton" > < / d i v >
Attach a File
2023-07-20 19:32:15 +02:00
< / d i v > ` ) ;
$ ( '#extensionsMenu' ) . prepend ( sendButton ) ;
2023-11-18 18:23:58 +01:00
$ ( '#extensionsMenu' ) . prepend ( attachFileButton ) ;
2023-09-11 23:15:21 +02:00
$ ( sendButton ) . on ( 'click' , ( ) => {
2023-11-07 00:28:46 +01:00
const hasCaptionModule =
( modules . includes ( 'caption' ) && extension _settings . caption . source === 'extras' ) ||
2023-12-19 23:45:45 +01:00
( extension _settings . caption . source === 'multimodal' && extension _settings . caption . multimodal _api === 'openai' && ( secret _state [ SECRET _KEYS . OPENAI ] || extension _settings . caption . allow _reverse _proxy ) ) ||
2023-11-17 22:19:21 +01:00
( extension _settings . caption . source === 'multimodal' && extension _settings . caption . multimodal _api === 'openrouter' && secret _state [ SECRET _KEYS . OPENROUTER ] ) ||
2023-12-14 13:37:53 +01:00
( extension _settings . caption . source === 'multimodal' && extension _settings . caption . multimodal _api === 'google' && secret _state [ SECRET _KEYS . MAKERSUITE ] ) ||
2024-03-04 22:07:38 +01:00
( extension _settings . caption . source === 'multimodal' && extension _settings . caption . multimodal _api === 'anthropic' && secret _state [ SECRET _KEYS . CLAUDE ] ) ||
2023-12-19 23:45:45 +01:00
( extension _settings . caption . source === 'multimodal' && extension _settings . caption . multimodal _api === 'ollama' && textgenerationwebui _settings . server _urls [ textgen _types . OLLAMA ] ) ||
( extension _settings . caption . source === 'multimodal' && extension _settings . caption . multimodal _api === 'llamacpp' && textgenerationwebui _settings . server _urls [ textgen _types . LLAMACPP ] ) ||
2023-12-24 00:43:29 +01:00
( extension _settings . caption . source === 'multimodal' && extension _settings . caption . multimodal _api === 'ooba' && textgenerationwebui _settings . server _urls [ textgen _types . OOBA ] ) ||
2023-12-20 20:05:20 +01:00
( extension _settings . caption . source === 'multimodal' && extension _settings . caption . multimodal _api === 'custom' ) ||
2023-11-07 00:28:46 +01:00
extension _settings . caption . source === 'local' ||
extension _settings . caption . source === 'horde' ;
2023-09-11 23:15:21 +02:00
if ( ! hasCaptionModule ) {
2023-11-17 22:19:21 +01:00
toastr . error ( 'Choose other captioning source in the extension settings.' , 'Captioning is not available' ) ;
2023-09-11 23:15:21 +02:00
return ;
}
$ ( '#img_file' ) . trigger ( 'click' ) ;
} ) ;
2023-07-20 19:32:15 +02:00
}
function addPictureSendForm ( ) {
2023-12-02 19:04:51 +01:00
const inputHtml = '<input id="img_file" type="file" hidden accept="image/*">' ;
2023-07-20 19:32:15 +02:00
const imgForm = document . createElement ( 'form' ) ;
imgForm . id = 'img_form' ;
$ ( imgForm ) . append ( inputHtml ) ;
$ ( imgForm ) . hide ( ) ;
$ ( '#form_sheld' ) . append ( imgForm ) ;
$ ( '#img_file' ) . on ( 'change' , onSelectImage ) ;
}
2023-11-17 22:19:21 +01:00
function switchMultimodalBlocks ( ) {
const isMultimodal = extension _settings . caption . source === 'multimodal' ;
$ ( '#caption_multimodal_block' ) . toggle ( isMultimodal ) ;
$ ( '#caption_prompt_block' ) . toggle ( isMultimodal ) ;
$ ( '#caption_multimodal_api' ) . val ( extension _settings . caption . multimodal _api ) ;
$ ( '#caption_multimodal_model' ) . val ( extension _settings . caption . multimodal _model ) ;
2023-12-17 18:41:20 +01:00
$ ( '#caption_multimodal_block [data-type]' ) . each ( function ( ) {
2023-11-17 22:19:21 +01:00
const type = $ ( this ) . data ( 'type' ) ;
2024-03-05 17:47:00 +01:00
const types = type . split ( ',' ) ;
$ ( this ) . toggle ( types . includes ( extension _settings . caption . multimodal _api ) ) ;
2023-11-17 22:19:21 +01:00
} ) ;
$ ( '#caption_multimodal_api' ) . on ( 'change' , ( ) => {
const api = String ( $ ( '#caption_multimodal_api' ) . val ( ) ) ;
const model = String ( $ ( ` #caption_multimodal_model option[data-type=" ${ api } "] ` ) . first ( ) . val ( ) ) ;
extension _settings . caption . multimodal _api = api ;
extension _settings . caption . multimodal _model = model ;
saveSettingsDebounced ( ) ;
switchMultimodalBlocks ( ) ;
} ) ;
$ ( '#caption_multimodal_model' ) . on ( 'change' , ( ) => {
extension _settings . caption . multimodal _model = String ( $ ( '#caption_multimodal_model' ) . val ( ) ) ;
saveSettingsDebounced ( ) ;
} ) ;
}
2023-07-20 19:32:15 +02:00
function addSettings ( ) {
const html = `
2023-09-13 00:40:01 +02:00
< div class = "caption_settings" >
2023-07-20 19:32:15 +02:00
< div class = "inline-drawer" >
< div class = "inline-drawer-toggle inline-drawer-header" >
< b > Image Captioning < / b >
< div class = "inline-drawer-icon fa-solid fa-circle-chevron-down down" > < / d i v >
< / d i v >
< div class = "inline-drawer-content" >
2023-11-18 20:17:53 +01:00
< label for = "caption_source" > Source < / l a b e l >
2023-11-07 00:58:34 +01:00
< select id = "caption_source" class = "text_pole" >
2023-11-07 00:28:46 +01:00
< option value = "local" > Local < / o p t i o n >
2024-03-04 22:07:38 +01:00
< option value = "multimodal" > Multimodal ( OpenAI / Anthropic / llama / Google ) < / o p t i o n >
2023-11-07 00:28:46 +01:00
< option value = "extras" > Extras < / o p t i o n >
< option value = "horde" > Horde < / o p t i o n >
< / s e l e c t >
2023-11-17 22:19:21 +01:00
< div id = "caption_multimodal_block" class = "flex-container wide100p" >
< div class = "flex1 flex-container flexFlowColumn flexNoGap" >
< label for = "caption_multimodal_api" > API < / l a b e l >
< select id = "caption_multimodal_api" class = "flex1 text_pole" >
2023-12-19 23:45:45 +01:00
< option value = "llamacpp" > llama . cpp < / o p t i o n >
2023-12-24 00:43:29 +01:00
< option value = "ooba" > Text Generation WebUI ( oobabooga ) < / o p t i o n >
2023-12-19 23:45:45 +01:00
< option value = "ollama" > Ollama < / o p t i o n >
2023-11-17 22:19:21 +01:00
< option value = "openai" > OpenAI < / o p t i o n >
2024-03-04 22:07:38 +01:00
< option value = "anthropic" > Anthropic < / o p t i o n >
2023-11-17 22:19:21 +01:00
< option value = "openrouter" > OpenRouter < / o p t i o n >
2023-12-19 23:45:45 +01:00
< option value = "google" > Google MakerSuite < / o p t i o n >
2023-12-20 20:05:20 +01:00
< option value = "custom" > Custom ( OpenAI - compatible ) < / o p t i o n >
2023-11-17 22:19:21 +01:00
< / s e l e c t >
< / d i v >
< div class = "flex1 flex-container flexFlowColumn flexNoGap" >
< label for = "caption_multimodal_model" > Model < / l a b e l >
< select id = "caption_multimodal_model" class = "flex1 text_pole" >
< option data - type = "openai" value = "gpt-4-vision-preview" > gpt - 4 - vision - preview < / o p t i o n >
2024-03-04 22:07:38 +01:00
< option data - type = "anthropic" value = "claude-3-opus-20240229" > claude - 3 - opus - 20240229 < / o p t i o n >
< option data - type = "anthropic" value = "claude-3-sonnet-20240229" > claude - 3 - sonnet - 20240229 < / o p t i o n >
2023-12-14 13:37:53 +01:00
< option data - type = "google" value = "gemini-pro-vision" > gemini - pro - vision < / o p t i o n >
2023-11-17 22:19:21 +01:00
< option data - type = "openrouter" value = "openai/gpt-4-vision-preview" > openai / gpt - 4 - vision - preview < / o p t i o n >
< option data - type = "openrouter" value = "haotian-liu/llava-13b" > haotian - liu / llava - 13 b < / o p t i o n >
2023-12-19 23:45:45 +01:00
< option data - type = "ollama" value = "ollama_current" > [ Currently selected ] < / o p t i o n >
< option data - type = "ollama" value = "bakllava:latest" > bakllava : latest < / o p t i o n >
< option data - type = "ollama" value = "llava:latest" > llava : latest < / o p t i o n >
< option data - type = "llamacpp" value = "llamacpp_current" > [ Currently loaded ] < / o p t i o n >
2023-12-24 00:43:29 +01:00
< option data - type = "ooba" value = "ooba_current" > [ Currently loaded ] < / o p t i o n >
2023-12-20 20:05:20 +01:00
< option data - type = "custom" value = "custom_current" > [ Currently selected ] < / o p t i o n >
2023-11-17 22:19:21 +01:00
< / s e l e c t >
< / d i v >
2024-03-05 17:47:00 +01:00
< label data - type = "openai,anthropic" class = "checkbox_label flexBasis100p" for = "caption_allow_reverse_proxy" title = "Allow using reverse proxy if defined and valid." >
2023-12-17 18:41:20 +01:00
< input id = "caption_allow_reverse_proxy" type = "checkbox" class = "checkbox" >
Allow reverse proxy
< / l a b e l >
2023-12-19 23:45:45 +01:00
< div class = "flexBasis100p m-b-1" >
< small > < b > Hint : < / b > S e t y o u r A P I k e y s a n d e n d p o i n t s i n t h e ' A P I C o n n e c t i o n s ' t a b f i r s t . < / s m a l l >
< / d i v >
2023-11-17 22:19:21 +01:00
< / d i v >
< div id = "caption_prompt_block" >
2023-11-18 20:17:53 +01:00
< label for = "caption_prompt" > Caption Prompt < / l a b e l >
2023-11-17 22:19:21 +01:00
< textarea id = "caption_prompt" class = "text_pole" rows = "1" placeholder = "< Use default >" > $ { PROMPT _DEFAULT } < / t e x t a r e a >
2023-12-20 20:23:59 +01:00
< label class = "checkbox_label margin-bot-10px" for = "caption_prompt_ask" title = "Ask for a custom prompt every time an image is captioned." >
< input id = "caption_prompt_ask" type = "checkbox" class = "checkbox" >
Ask every time
< / l a b e l >
2023-11-17 22:19:21 +01:00
< / d i v >
2023-11-18 20:17:53 +01:00
< label for = "caption_template" > Message Template < small > ( use < code > { { caption } } < / c o d e > m a c r o ) < / s m a l l > < / l a b e l >
2023-11-07 00:58:34 +01:00
< textarea id = "caption_template" class = "text_pole" rows = "2" placeholder = "< Use default >" > $ { TEMPLATE _DEFAULT } < / t e x t a r e a >
2023-11-07 00:28:46 +01:00
< label class = "checkbox_label margin-bot-10px" for = "caption_refine_mode" >
2023-07-20 19:32:15 +02:00
< input id = "caption_refine_mode" type = "checkbox" class = "checkbox" >
2023-11-18 20:17:53 +01:00
Edit captions before saving
2023-07-20 19:32:15 +02:00
< / l a b e l >
< / d i v >
< / d i v >
< / d i v >
` ;
$ ( '#extensions_settings2' ) . append ( html ) ;
}
addSettings ( ) ;
addPictureSendForm ( ) ;
addSendPictureButton ( ) ;
setImageIcon ( ) ;
2023-11-07 00:58:34 +01:00
migrateSettings ( ) ;
2023-11-17 22:19:21 +01:00
switchMultimodalBlocks ( ) ;
2023-11-07 00:28:46 +01:00
2023-07-20 19:32:15 +02:00
$ ( '#caption_refine_mode' ) . prop ( 'checked' , ! ! ( extension _settings . caption . refine _mode ) ) ;
2023-12-17 18:41:20 +01:00
$ ( '#caption_allow_reverse_proxy' ) . prop ( 'checked' , ! ! ( extension _settings . caption . allow _reverse _proxy ) ) ;
2023-12-20 20:23:59 +01:00
$ ( '#caption_prompt_ask' ) . prop ( 'checked' , ! ! ( extension _settings . caption . prompt _ask ) ) ;
2023-11-07 00:28:46 +01:00
$ ( '#caption_source' ) . val ( extension _settings . caption . source ) ;
2023-11-07 00:58:34 +01:00
$ ( '#caption_prompt' ) . val ( extension _settings . caption . prompt ) ;
$ ( '#caption_template' ) . val ( extension _settings . caption . template ) ;
2023-07-20 19:32:15 +02:00
$ ( '#caption_refine_mode' ) . on ( 'input' , onRefineModeInput ) ;
2023-11-07 00:28:46 +01:00
$ ( '#caption_source' ) . on ( 'change' , ( ) => {
extension _settings . caption . source = String ( $ ( '#caption_source' ) . val ( ) ) ;
2023-11-17 22:19:21 +01:00
switchMultimodalBlocks ( ) ;
2023-09-11 23:15:21 +02:00
saveSettingsDebounced ( ) ;
} ) ;
2023-11-07 00:58:34 +01:00
$ ( '#caption_prompt' ) . on ( 'input' , ( ) => {
extension _settings . caption . prompt = String ( $ ( '#caption_prompt' ) . val ( ) ) ;
saveSettingsDebounced ( ) ;
} ) ;
$ ( '#caption_template' ) . on ( 'input' , ( ) => {
extension _settings . caption . template = String ( $ ( '#caption_template' ) . val ( ) ) ;
saveSettingsDebounced ( ) ;
} ) ;
2023-12-17 18:41:20 +01:00
$ ( '#caption_allow_reverse_proxy' ) . on ( 'input' , ( ) => {
extension _settings . caption . allow _reverse _proxy = $ ( '#caption_allow_reverse_proxy' ) . prop ( 'checked' ) ;
saveSettingsDebounced ( ) ;
} ) ;
2023-12-20 20:23:59 +01:00
$ ( '#caption_prompt_ask' ) . on ( 'input' , ( ) => {
extension _settings . caption . prompt _ask = $ ( '#caption_prompt_ask' ) . prop ( 'checked' ) ;
saveSettingsDebounced ( ) ;
} ) ;
2023-07-20 19:32:15 +02:00
} ) ;