Caption: Improve Ollama models handling
| @@ -588,10 +588,12 @@ jQuery(async function () { | |||
| 588 | saveSettingsDebounced(); | 588 | saveSettingsDebounced(); |
| 589 | }); | 589 | }); |
| 590 | $('#caption_ollama_pull').on('click', (e) => { | 590 | $('#caption_ollama_pull').on('click', (e) => { |
| 591 | const presetModel = extension_settings.caption.multimodal_model !== 'ollama_current' ? extension_settings.caption.multimodal_model : ''; | 591 | const selectedModel = extension_settings.caption.multimodal_model; |
| 592 | const staticModels = { 'ollama_current': textgenerationwebui_settings.ollama_model, 'ollama_custom': extension_settings.caption.ollama_custom_model }; | ||
| 593 | const presetModel = staticModels[selectedModel] || selectedModel; | ||
| 592 | e.preventDefault(); | 594 | e.preventDefault(); |
| 593 | $('#ollama_download_model').trigger('click'); | 595 | $('#ollama_download_model').trigger('click'); |
| 594 | $('#dialogue_popup_input').val(presetModel); | 596 | $('.popup .popup-input').val(presetModel); |
| 595 | }); | 597 | }); |
| 596 | $('#caption_multimodal_api').on('change', async () => { | 598 | $('#caption_multimodal_api').on('change', async () => { |
| 597 | const api = String($('#caption_multimodal_api').val()); | 599 | const api = String($('#caption_multimodal_api').val()); |
| @@ -616,6 +618,10 @@ jQuery(async function () { | |||
| 616 | extension_settings.caption.show_in_chat = !!$('#caption_show_in_chat').prop('checked'); | 618 | extension_settings.caption.show_in_chat = !!$('#caption_show_in_chat').prop('checked'); |
| 617 | saveSettingsDebounced(); | 619 | saveSettingsDebounced(); |
| 618 | }); | 620 | }); |
| 621 | $('#caption_ollama_custom_model').val(extension_settings.caption.ollama_custom_model || '').on('input', () => { | ||
| 622 | extension_settings.caption.ollama_custom_model = String($('#caption_ollama_custom_model').val()).trim(); | ||
| 623 | saveSettingsDebounced(); | ||
| 624 | }); | ||
| 619 | 625 | ||
| 620 | const onMessageEvent = async (index) => { | 626 | const onMessageEvent = async (index) => { |
| 621 | if (!extension_settings.caption.auto_mode) { | 627 | if (!extension_settings.caption.auto_mode) { |
| @@ -154,11 +154,20 @@ | |||
| 154 | <option data-type="groq" value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview</option> | 154 | <option data-type="groq" value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview</option> |
| 155 | <option data-type="groq" value="llava-v1.5-7b-4096-preview">llava-v1.5-7b-4096-preview</option> | 155 | <option data-type="groq" value="llava-v1.5-7b-4096-preview">llava-v1.5-7b-4096-preview</option> |
| 156 | <option data-type="ollama" value="ollama_current" data-i18n="currently_selected">[Currently selected]</option> | 156 | <option data-type="ollama" value="ollama_current" data-i18n="currently_selected">[Currently selected]</option> |
| 157 | <option data-type="ollama" value="ollama_custom" data-i18n="[Custom model]">[Custom model]</option> | ||
| 157 | <option data-type="ollama" value="bakllava">bakllava</option> | 158 | <option data-type="ollama" value="bakllava">bakllava</option> |
| 158 | <option data-type="ollama" value="llava">llava</option> | 159 | <option data-type="ollama" value="llava">llava</option> |
| 159 | <option data-type="ollama" value="llava-llama3">llava-llama3</option> | 160 | <option data-type="ollama" value="llava-llama3">llava-llama3</option> |
| 160 | <option data-type="ollama" value="llava-phi3">llava-phi3</option> | 161 | <option data-type="ollama" value="llava-phi3">llava-phi3</option> |
| 161 | <option data-type="ollama" value="moondream">moondream</option> | 162 | <option data-type="ollama" value="moondream">moondream</option> |
| 163 | <option data-type="ollama" value="gemma3">gemma3</option> | ||
| 164 | <option data-type="ollama" value="minicpm-v">minicpm-v</option> | ||
| 165 | <option data-type="ollama" value="qwen2.5vl">qwen2.5vl</option> | ||
| 166 | <option data-type="ollama" value="granite3.2-vision">granite3.2-vision</option> | ||
| 167 | <option data-type="ollama" value="mistral-small3.1">mistral-small3.1</option> | ||
| 168 | <option data-type="ollama" value="mistral-small3.2">mistral-small3.2</option> | ||
| 169 | <option data-type="ollama" value="llama3.2-vision">llama3.2-vision</option> | ||
| 170 | <option data-type="ollama" value="llama4">llama4</option> | ||
| 162 | <option data-type="llamacpp" value="llamacpp_current" data-i18n="currently_loaded">[Currently loaded]</option> | 171 | <option data-type="llamacpp" value="llamacpp_current" data-i18n="currently_loaded">[Currently loaded]</option> |
| 163 | <option data-type="ooba" value="ooba_current" data-i18n="currently_loaded">[Currently loaded]</option> | 172 | <option data-type="ooba" value="ooba_current" data-i18n="currently_loaded">[Currently loaded]</option> |
| 164 | <option data-type="koboldcpp" value="koboldcpp_current" data-i18n="currently_loaded">[Currently loaded]</option> | 173 | <option data-type="koboldcpp" value="koboldcpp_current" data-i18n="currently_loaded">[Currently loaded]</option> |
| @@ -170,16 +179,25 @@ | |||
| 170 | </select> | 179 | </select> |
| 171 | </div> | 180 | </div> |
| 172 | <div data-type="ollama"> | 181 | <div data-type="ollama"> |
| 173 | The model must be downloaded first! Do it with the <code>ollama pull</code> command or <a href="#" id="caption_ollama_pull">click here</a>. | 182 | <div> |
| 183 | The model must be downloaded first! Do it with the <code>ollama pull</code> command or <a href="#" id="caption_ollama_pull">click here</a>. | ||
| 184 | </div> | ||
| 185 | <div class="marginTop5"> | ||
| 186 | <label for="caption_ollama_custom_model"> | ||
| 187 | <span data-i18n="Custom Model Tag">Custom Model Tag</span> | ||
| 188 | <small data-i18n="(for [Custom model] option)">(for [Custom model] option)</small> | ||
| 189 | </label> | ||
| 190 | <input id="caption_ollama_custom_model" class="text_pole" type="text" placeholder="e.g. gemma3:latest" /> | ||
| 191 | </div> | ||
| 174 | </div> | 192 | </div> |
| 175 | <label data-type="openai,anthropic,google,vertexai,mistral,xai" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid."> | 193 | <label data-type="openai,anthropic,google,vertexai,mistral,xai" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid."> |
| 176 | <input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox"> | 194 | <input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox"> |
| 177 | <span data-i18n="Allow reverse proxy">Allow reverse proxy</span> | 195 | <span data-i18n="Allow reverse proxy">Allow reverse proxy</span> |
| 178 | </label> | 196 | </label> |
| 179 | <div class="flexBasis100p m-b-1"> | 197 | <div class="flexBasis100p marginBot10"> |
| 180 | <small><b data-i18n="Hint:">Hint:</b> <span data-i18n="Set your API keys and endpoints in the 'API Connections' tab first.">Set your API keys and endpoints in the 'API Connections' tab first.</span></small> | 198 | <small><b data-i18n="Hint:">Hint:</b> <span data-i18n="Set your API keys and endpoints in the 'API Connections' tab first.">Set your API keys and endpoints in the 'API Connections' tab first.</span></small> |
| 181 | </div> | 199 | </div> |
| 182 | <div data-type="koboldcpp,ollama,vllm,llamacpp,ooba" class="flex-container flexFlowColumn"> | 200 | <div data-type="koboldcpp,ollama,vllm,llamacpp,ooba" class="flex-container flexFlowColumn wide100p"> |
| 183 | <label for="caption_altEndpoint_enabled" class="checkbox_label"> | 201 | <label for="caption_altEndpoint_enabled" class="checkbox_label"> |
| 184 | <input id="caption_altEndpoint_enabled" type="checkbox"> | 202 | <input id="caption_altEndpoint_enabled" type="checkbox"> |
| 185 | <span data-i18n="Use secondary URL">Use secondary URL</span> | 203 | <span data-i18n="Use secondary URL">Use secondary URL</span> |
| @@ -22,12 +22,6 @@ export async function getMultimodalCaption(base64Img, prompt) { | |||
| 22 | 22 | ||
| 23 | throwIfInvalidModel(useReverseProxy); | 23 | throwIfInvalidModel(useReverseProxy); |
| 24 | 24 | ||
| 25 | const noPrefix = ['ollama'].includes(extension_settings.caption.multimodal_api); | ||
| 26 | |||
| 27 | if (noPrefix && base64Img.startsWith('data:image/')) { | ||
| 28 | base64Img = base64Img.split(',')[1]; | ||
| 29 | } | ||
| 30 | |||
| 31 | // OpenRouter has a payload limit of ~2MB. Google is 4MB, but we love democracy. | 25 | // OpenRouter has a payload limit of ~2MB. Google is 4MB, but we love democracy. |
| 32 | // Ooba requires all images to be JPEGs. Koboldcpp just asked nicely. | 26 | // Ooba requires all images to be JPEGs. Koboldcpp just asked nicely. |
| 33 | const isOllama = extension_settings.caption.multimodal_api === 'ollama'; | 27 | const isOllama = extension_settings.caption.multimodal_api === 'ollama'; |
| @@ -47,6 +41,9 @@ export async function getMultimodalCaption(base64Img, prompt) { | |||
| 47 | } else if (!safeMimeTypes.includes(mimeType)) { | 41 | } else if (!safeMimeTypes.includes(mimeType)) { |
| 48 | base64Img = await createThumbnail(base64Img, null, null); | 42 | base64Img = await createThumbnail(base64Img, null, null); |
| 49 | } | 43 | } |
| 44 | if (isOllama && base64Img.startsWith('data:image/')) { | ||
| 45 | base64Img = base64Img.split(',')[1]; | ||
| 46 | } | ||
| 50 | 47 | ||
| 51 | const proxyUrl = useReverseProxy ? oai_settings.reverse_proxy : ''; | 48 | const proxyUrl = useReverseProxy ? oai_settings.reverse_proxy : ''; |
| 52 | const proxyPassword = useReverseProxy ? oai_settings.proxy_password : ''; | 49 | const proxyPassword = useReverseProxy ? oai_settings.proxy_password : ''; |
| @@ -72,6 +69,10 @@ export async function getMultimodalCaption(base64Img, prompt) { | |||
| 72 | requestBody.model = textgenerationwebui_settings.ollama_model; | 69 | requestBody.model = textgenerationwebui_settings.ollama_model; |
| 73 | } | 70 | } |
| 74 | 71 | ||
| 72 | if (extension_settings.caption.multimodal_model === 'ollama_custom') { | ||
| 73 | requestBody.model = extension_settings.caption.ollama_custom_model; | ||
| 74 | } | ||
| 75 | |||
| 75 | requestBody.server_url = extension_settings.caption.alt_endpoint_enabled | 76 | requestBody.server_url = extension_settings.caption.alt_endpoint_enabled |
| 76 | ? extension_settings.caption.alt_endpoint_url | 77 | ? extension_settings.caption.alt_endpoint_url |
| 77 | : textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]; | 78 | : textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]; |
| @@ -211,6 +212,10 @@ function throwIfInvalidModel(useReverseProxy) { | |||
| 211 | throw new Error('Ollama model is not set.'); | 212 | throw new Error('Ollama model is not set.'); |
| 212 | } | 213 | } |
| 213 | 214 | ||
| 215 | if (multimodalApi === 'ollama' && multimodalModel === 'ollama_custom' && !extension_settings.caption.ollama_custom_model) { | ||
| 216 | throw new Error('Ollama custom model tag is not set.'); | ||
| 217 | } | ||
| 218 | |||
| 214 | if (multimodalApi === 'llamacpp' && !textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP] && !altEndpointEnabled) { | 219 | if (multimodalApi === 'llamacpp' && !textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP] && !altEndpointEnabled) { |
| 215 | throw new Error('LlamaCPP server URL is not set.'); | 220 | throw new Error('LlamaCPP server URL is not set.'); |
| 216 | } | 221 | } |
| @@ -478,7 +478,8 @@ ollama.post('/caption-image', async function (request, response) { | |||
| 478 | }); | 478 | }); |
| 479 | 479 | ||
| 480 | if (!fetchResponse.ok) { | 480 | if (!fetchResponse.ok) { |
| 481 | console.error('Ollama caption error:', fetchResponse.status, fetchResponse.statusText); | 481 | const errorText = await fetchResponse.text(); |
| 482 | console.error('Ollama caption error:', fetchResponse.status, fetchResponse.statusText, errorText); | ||
| 482 | return response.status(500).send({ error: true }); | 483 | return response.status(500).send({ error: true }); |
| 483 | } | 484 | } |
| 484 | 485 | ||