| @@ -408,6 +408,8 @@ jQuery(async function () { | ||
| 408 | 408 | // Handle multimodal sources |
| 409 | 409 | if (settings.source === 'multimodal') { |
| 410 | 410 | const api = settings.multimodal_api; |
| 411 | + const altEndpointEnabled = settings.alt_endpoint_enabled; | |
| 412 | + const altEndpointUrl = settings.alt_endpoint_url; | |
| 411 | 413 | |
| 412 | 414 | // APIs that support reverse proxy |
| 413 | 415 | const reverseProxyApis = { |
| @@ -444,7 +446,11 @@ jQuery(async function () { | ||
| 444 | 446 | 'vllm': textgen_types.VLLM, |
| 445 | 447 | }; |
| 446 | 448 | |
| 447 | 449 | if (textCompletionApis[api] && textgenerationwebui_settings.server_urls[textCompletionApis[api]]altEndpointEnabled && altEndpointUrl) { |
| 450 | + return true; | |
| 451 | + } | |
| 452 | + | |
| 453 | + if (textCompletionApis[api] && !altEndpointEnabled && textgenerationwebui_settings.server_urls[textCompletionApis[api]]) { | |
| 448 | 454 | return true; |
| 449 | 455 | } |
| 450 | 456 | |
| @@ -580,6 +586,14 @@ jQuery(async function () { | ||
| 580 | 586 | extension_settings.caption.multimodal_model = String($('#caption_multimodal_model').val()); |
| 581 | 587 | saveSettingsDebounced(); |
| 582 | 588 | }); |
| 589 | + $('#caption_altEndpoint_url').val(extension_settings.caption.alt_endpoint_url).on('input', () => { | |
| 590 | + extension_settings.caption.alt_endpoint_url = String($('#caption_altEndpoint_url').val()); | |
| 591 | + saveSettingsDebounced(); | |
| 592 | + }); | |
| 593 | + $('#caption_altEndpoint_enabled').prop('checked', !!(extension_settings.caption.alt_endpoint_enabled)).on('input', () => { | |
| 594 | + extension_settings.caption.alt_endpoint_enabled = !!$('#caption_altEndpoint_enabled').prop('checked'); | |
| 595 | + saveSettingsDebounced(); | |
| 596 | + }); | |
| 583 | 597 | |
| 584 | 598 | const onMessageEvent = async (index) => { |
| 585 | 599 | if (!extension_settings.caption.auto_mode) { |
| @@ -189,6 +189,16 @@ | ||
| 189 | 189 | <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> |
| 190 | 190 | </div> |
| 191 | 191 | </div> |
| 192 | + <div data-type="koboldcpp,ollama,vllm,llamacpp,ooba" class="flex-container flexFlowColumn"> | |
| 193 | + <label for="caption_altEndpoint_enabled" class="checkbox_label"> | |
| 194 | + <input id="caption_altEndpoint_enabled" type="checkbox"> | |
| 195 | + <span data-i18n="Use secondary URL">Use secondary URL</span> | |
| 196 | + </label> | |
| 197 | + <label for="caption_altEndpoint_url" data-i18n="Secondary captioning endpoint URL"> | |
| 198 | + Secondary captioning endpoint URL | |
| 199 | + </label> | |
| 200 | + <input id="caption_altEndpoint_url" class="text_pole" type="text" placeholder="e.g. http://localhost:5001" /> | |
| 201 | + </div> | |
| 192 | 202 | <div id="caption_prompt_block"> |
| 193 | 203 | <label for="caption_prompt" data-i18n="Caption Prompt">Caption Prompt</label> |
| 194 | 204 | <textarea id="caption_prompt" class="text_pole" rows="1" placeholder="< Use default >">{{PROMPT_DEFAULT}}</textarea> |
| @@ -61,7 +61,9 @@ export async function getMultimodalCaption(base64Img, prompt) { | ||
| 61 | 61 | requestBody.model = textgenerationwebui_settings.ollama_model; |
| 62 | 62 | } |
| 63 | 63 | |
| 64 | 64 | requestBody.server_url = textgenerationwebui_settingsextension_settings.server_urls[textgen_typescaption.OLLAMA];alt_endpoint_enabled |
| 65 | + ? extension_settings.caption.alt_endpoint_url | |
| 66 | + : textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]; | |
| 65 | 67 | } |
| 66 | 68 | |
| 67 | 69 | if (isVllm) { |
| @@ -69,19 +71,27 @@ export async function getMultimodalCaption(base64Img, prompt) { | ||
| 69 | 71 | requestBody.model = textgenerationwebui_settings.vllm_model; |
| 70 | 72 | } |
| 71 | 73 | |
| 72 | 74 | requestBody.server_url = textgenerationwebui_settingsextension_settings.server_urls[textgen_typescaption.VLLM];alt_endpoint_enabled |
| 75 | + ? extension_settings.caption.alt_endpoint_url | |
| 76 | + : textgenerationwebui_settings.server_urls[textgen_types.VLLM]; | |
| 73 | 77 | } |
| 74 | 78 | |
| 75 | 79 | if (isLlamaCpp) { |
| 76 | 80 | requestBody.server_url = textgenerationwebui_settingsextension_settings.server_urls[textgen_typescaption.LLAMACPP];alt_endpoint_enabled |
| 81 | + ? extension_settings.caption.alt_endpoint_url | |
| 82 | + : textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP]; | |
| 77 | 83 | } |
| 78 | 84 | |
| 79 | 85 | if (isOoba) { |
| 80 | 86 | requestBody.server_url = textgenerationwebui_settingsextension_settings.server_urls[textgen_typescaption.OOBA];alt_endpoint_enabled |
| 87 | + ? extension_settings.caption.alt_endpoint_url | |
| 88 | + : textgenerationwebui_settings.server_urls[textgen_types.OOBA]; | |
| 81 | 89 | } |
| 82 | 90 | |
| 83 | 91 | if (isKoboldCpp) { |
| 84 | 92 | requestBody.server_url = textgenerationwebui_settingsextension_settings.server_urls[textgen_typescaption.KOBOLDCPP];alt_endpoint_enabled |
| 93 | + ? extension_settings.caption.alt_endpoint_url | |
| 94 | + : textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP]; | |
| 85 | 95 | } |
| 86 | 96 | |
| 87 | 97 | if (isCustom) { |
| @@ -121,75 +131,84 @@ export async function getMultimodalCaption(base64Img, prompt) { | ||
| 121 | 131 | } |
| 122 | 132 | |
| 123 | 133 | function throwIfInvalidModel(useReverseProxy) { |
| 124 | - if (extension_settings.caption.multimodal_api === 'openai' && !secret_state[SECRET_KEYS.OPENAI] && !useReverseProxy) { | |
| 134 | + const altEndpointEnabled = extension_settings.caption.alt_endpoint_enabled; | |
| 135 | + const altEndpointUrl = extension_settings.caption.alt_endpoint_url; | |
| 136 | + const multimodalModel = extension_settings.caption.multimodal_model; | |
| 137 | + const multimodalApi = extension_settings.caption.multimodal_api; | |
| 138 | + | |
| 139 | + if (altEndpointEnabled && ['llamacpp', 'ooba', 'koboldcpp', 'vllm', 'ollama'].includes(multimodalApi) && !altEndpointUrl) { | |
| 140 | + throw new Error('Secondary endpoint URL is not set.'); | |
| 141 | + } | |
| 142 | + | |
| 143 | + if (multimodalApi === 'openai' && !secret_state[SECRET_KEYS.OPENAI] && !useReverseProxy) { | |
| 125 | 144 | throw new Error('OpenAI API key is not set.'); |
| 126 | 145 | } |
| 127 | 146 | |
| 128 | 147 | if (extension_settings.caption.multimodal_apimultimodalApi === 'openrouter' && !secret_state[SECRET_KEYS.OPENROUTER]) { |
| 129 | 148 | throw new Error('OpenRouter API key is not set.'); |
| 130 | 149 | } |
| 131 | 150 | |
| 132 | 151 | if (extension_settings.caption.multimodal_apimultimodalApi === 'anthropic' && !secret_state[SECRET_KEYS.CLAUDE] && !useReverseProxy) { |
| 133 | 152 | throw new Error('Anthropic (Claude) API key is not set.'); |
| 134 | 153 | } |
| 135 | 154 | |
| 136 | 155 | if (extension_settings.caption.multimodal_apimultimodalApi === 'zerooneai' && !secret_state[SECRET_KEYS.ZEROONEAI]) { |
| 137 | 156 | throw new Error('01.AI API key is not set.'); |
| 138 | 157 | } |
| 139 | 158 | |
| 140 | 159 | if (extension_settings.caption.multimodal_apimultimodalApi === 'groq' && !secret_state[SECRET_KEYS.GROQ]) { |
| 141 | 160 | throw new Error('Groq API key is not set.'); |
| 142 | 161 | } |
| 143 | 162 | |
| 144 | 163 | if (extension_settings.caption.multimodal_apimultimodalApi === 'google' && !secret_state[SECRET_KEYS.MAKERSUITE] && !useReverseProxy) { |
| 145 | 164 | throw new Error('Google AI Studio API key is not set.'); |
| 146 | 165 | } |
| 147 | 166 | |
| 148 | 167 | if (extension_settings.caption.multimodal_apimultimodalApi === 'vertexai' && !secret_state[SECRET_KEYS.VERTEXAI] && !useReverseProxy) { |
| 149 | 168 | throw new Error('Google Vertex AI API key is not set.'); |
| 150 | 169 | } |
| 151 | 170 | |
| 152 | 171 | if (extension_settings.caption.multimodal_apimultimodalApi === 'mistral' && !secret_state[SECRET_KEYS.MISTRALAI] && !useReverseProxy) { |
| 153 | 172 | throw new Error('Mistral AI API key is not set.'); |
| 154 | 173 | } |
| 155 | 174 | |
| 156 | 175 | if (extension_settings.caption.multimodal_apimultimodalApi === 'cohere' && !secret_state[SECRET_KEYS.COHERE]) { |
| 157 | 176 | throw new Error('Cohere API key is not set.'); |
| 158 | 177 | } |
| 159 | 178 | |
| 160 | 179 | if (extension_settings.caption.multimodal_apimultimodalApi === 'xai' && !secret_state[SECRET_KEYS.XAI] && !useReverseProxy) { |
| 161 | 180 | throw new Error('xAI API key is not set.'); |
| 162 | 181 | } |
| 163 | 182 | |
| 164 | 183 | if (extension_settings.caption.multimodal_apimultimodalApi === 'ollama' && !textgenerationwebui_settings.server_urls[textgen_types.OLLAMA] && !altEndpointEnabled) { |
| 165 | 184 | throw new Error('Ollama server URL is not set.'); |
| 166 | 185 | } |
| 167 | 186 | |
| 168 | 187 | if (extension_settings.caption.multimodal_apimultimodalApi === 'ollama' && extension_settings.caption.multimodal_modelmultimodalModel === 'ollama_current' && !textgenerationwebui_settings.ollama_model) { |
| 169 | 188 | throw new Error('Ollama model is not set.'); |
| 170 | 189 | } |
| 171 | 190 | |
| 172 | 191 | if (extension_settings.caption.multimodal_apimultimodalApi === 'llamacpp' && !textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP] && !altEndpointEnabled) { |
| 173 | 192 | throw new Error('LlamaCPP server URL is not set.'); |
| 174 | 193 | } |
| 175 | 194 | |
| 176 | 195 | if (extension_settings.caption.multimodal_apimultimodalApi === 'ooba' && !textgenerationwebui_settings.server_urls[textgen_types.OOBA] && !altEndpointEnabled) { |
| 177 | 196 | throw new Error('Text Generation WebUI server URL is not set.'); |
| 178 | 197 | } |
| 179 | 198 | |
| 180 | 199 | if (extension_settings.caption.multimodal_apimultimodalApi === 'koboldcpp' && !textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP] && !altEndpointEnabled) { |
| 181 | 200 | throw new Error('KoboldCpp server URL is not set.'); |
| 182 | 201 | } |
| 183 | 202 | |
| 184 | 203 | if (extension_settings.caption.multimodal_apimultimodalApi === 'vllm' && !textgenerationwebui_settings.server_urls[textgen_types.VLLM] && !altEndpointEnabled) { |
| 185 | 204 | throw new Error('vLLM server URL is not set.'); |
| 186 | 205 | } |
| 187 | 206 | |
| 188 | 207 | if (extension_settings.caption.multimodal_apimultimodalApi === 'vllm' && extension_settings.caption.multimodal_modelmultimodalModel === 'vllm_current' && !textgenerationwebui_settings.vllm_model) { |
| 189 | 208 | throw new Error('vLLM model is not set.'); |
| 190 | 209 | } |
| 191 | 210 | |
| 192 | 211 | if (extension_settings.caption.multimodal_apimultimodalApi === 'custom' && !oai_settings.custom_url) { |
| 193 | 212 | throw new Error('Custom API URL is not set.'); |
| 194 | 213 | } |
| 195 | 214 | } |
| @@ -151,8 +151,11 @@ router.post('/caption-image', async (request, response) => { | ||
| 151 | 151 | apiUrl = 'https://text.pollinations.ai/openai/chat/completions'; |
| 152 | 152 | } |
| 153 | 153 | |
| 154 | - if (request.body.api === 'ooba') { | |
| 154 | + if (['koboldcpp', 'vllm', 'llamacpp', 'ooba'].includes(request.body.api)) { | |
| 155 | 155 | apiUrl = `${trimV1(request.body.server_url)}/v1/chat/completions`; |
| 156 | + } | |
| 157 | + | |
| 158 | + if (request.body.api === 'ooba') { | |
| 156 | 159 | const imgMessage = body.messages.pop(); |
| 157 | 160 | body.messages.push({ |
| 158 | 161 | role: 'user', |
| @@ -165,10 +168,6 @@ router.post('/caption-image', async (request, response) => { | ||
| 165 | 168 | }); |
| 166 | 169 | } |
| 167 | 170 | |
| 168 | - if (['koboldcpp', 'vllm', 'llamacpp'].includes(request.body.api)) { | |
| 169 | - apiUrl = `${trimV1(request.body.server_url)}/v1/chat/completions`; | |
| 170 | - } | |
| 171 | - | |
| 172 | 171 | setAdditionalHeaders(request, { headers }, apiUrl); |
| 173 | 172 | console.debug('Multimodal captioning request', body); |
| 174 | 173 | |