MistralAI: Add Pixtral to models and captioning
| @@ -2896,6 +2896,7 @@ | ||
| 2896 | 2896 | <option value="mistral-large-latest">mistral-large-latest</option> |
| 2897 | 2897 | <option value="codestral-latest">codestral-latest</option> |
| 2898 | 2898 | <option value="codestral-mamba-latest">codestral-mamba-latest</option> |
| 2899 | + <option value="pixtral-latest">pixtral-latest</option> | |
| 2899 | 2900 | </optgroup> |
| 2900 | 2901 | <optgroup label="Sub-versions"> |
| 2901 | 2902 | <option value="open-mistral-nemo-2407">open-mistral-nemo-2407</option> |
| @@ -2903,11 +2904,13 @@ | ||
| 2903 | 2904 | <option value="mistral-tiny-2312">mistral-tiny-2312</option> |
| 2904 | 2905 | <option value="mistral-small-2312">mistral-small-2312</option> |
| 2905 | 2906 | <option value="mistral-small-2402">mistral-small-2402</option> |
| 2907 | + <option value="mistral-small-2409">mistral-small-2409</option> | |
| 2906 | 2908 | <option value="mistral-medium-2312">mistral-medium-2312</option> |
| 2907 | 2909 | <option value="mistral-large-2402">mistral-large-2402</option> |
| 2908 | 2910 | <option value="mistral-large-2407">mistral-large-2407</option> |
| 2909 | 2911 | <option value="codestral-2405">codestral-2405</option> |
| 2910 | 2912 | <option value="codestral-mamba-2407">codestral-mamba-2407</option> |
| 2913 | + <option value="pixtral-12b-2409">pixtral-12b-2409</option> | |
| 2911 | 2914 | </optgroup> |
| 2912 | 2915 | </select> |
| 2913 | 2916 | </div> |
| @@ -403,6 +403,7 @@ jQuery(async function () { | ||
| 403 | 403 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openai' && (secret_state[SECRET_KEYS.OPENAI] || extension_settings.caption.allow_reverse_proxy)) || |
| 404 | 404 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openrouter' && secret_state[SECRET_KEYS.OPENROUTER]) || |
| 405 | 405 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'zerooneai' && secret_state[SECRET_KEYS.ZEROONEAI]) || |
| 406 | + (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'mistral' && (secret_state[SECRET_KEYS.MISTRALAI] || extension_settings.caption.allow_reverse_proxy)) || | |
| 406 | 407 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'google' && (secret_state[SECRET_KEYS.MAKERSUITE] || extension_settings.caption.allow_reverse_proxy)) || |
| 407 | 408 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'anthropic' && (secret_state[SECRET_KEYS.CLAUDE] || extension_settings.caption.allow_reverse_proxy)) || |
| 408 | 409 | (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'ollama' && textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]) || |
| @@ -23,6 +23,7 @@ | ||
| 23 | 23 | <option value="google">Google AI Studio</option> |
| 24 | 24 | <option value="koboldcpp">KoboldCpp</option> |
| 25 | 25 | <option value="llamacpp">llama.cpp</option> |
| 26 | + <option value="mistral">MistralAI</option> | |
| 26 | 27 | <option value="ollama">Ollama</option> |
| 27 | 28 | <option value="openai">OpenAI</option> |
| 28 | 29 | <option value="openrouter">OpenRouter</option> |
| @@ -33,6 +34,8 @@ | ||
| 33 | 34 | <div class="flex1 flex-container flexFlowColumn flexNoGap"> |
| 34 | 35 | <label for="caption_multimodal_model" data-i18n="Model">Model</label> |
| 35 | 36 | <select id="caption_multimodal_model" class="flex1 text_pole"> |
| 37 | + <option data-type="mistral" value="pixtral-latest">pixtral-latest</option> | |
| 38 | + <option data-type="mistral" value="pixtral-12b-2409">pixtral-12b-2409</option> | |
| 36 | 39 | <option data-type="zerooneai" value="yi-vision">yi-vision</option> |
| 37 | 40 | <option data-type="openai" value="gpt-4-vision-preview">gpt-4-vision-preview</option> |
| 38 | 41 | <option data-type="openai" value="gpt-4-turbo">gpt-4-turbo</option> |
| @@ -96,7 +99,7 @@ | ||
| 96 | 99 | <div data-type="ollama"> |
| 97 | 100 | 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>. |
| 98 | 101 | </div> |
| 99 | 102 | <label data-type="openai,anthropic,google,mistral" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid."> |
| 100 | 103 | <input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox"> |
| 101 | 104 | <span data-i18n="Allow reverse proxy">Allow reverse proxy</span> |
| 102 | 105 | </label> |
| @@ -13,7 +13,7 @@ import { createThumbnail, isValidUrl } from '../utils.js'; | ||
| 13 | 13 | */ |
| 14 | 14 | export async function getMultimodalCaption(base64Img, prompt) { |
| 15 | 15 | const useReverseProxy = |
| 16 | 16 | (['openai', 'anthropic', 'google', 'mistral'].includes(extension_settings.caption.multimodal_api)) |
| 17 | 17 | && extension_settings.caption.allow_reverse_proxy |
| 18 | 18 | && oai_settings.reverse_proxy |
| 19 | 19 | && isValidUrl(oai_settings.reverse_proxy); |
| @@ -36,7 +36,7 @@ export async function getMultimodalCaption(base64Img, prompt) { | ||
| 36 | 36 | const isVllm = extension_settings.caption.multimodal_api === 'vllm'; |
| 37 | 37 | const base64Bytes = base64Img.length * 0.75; |
| 38 | 38 | const compressionLimit = 2 * 1024 * 1024; |
| 39 | 39 | if ((['google', 'openrouter', 'mistral'].includes(extension_settings.caption.multimodal_api) && base64Bytes > compressionLimit) || isOoba || isKoboldCpp) { |
| 40 | 40 | const maxSide = 1024; |
| 41 | 41 | base64Img = await createThumbnail(base64Img, maxSide, maxSide, 'image/jpeg'); |
| 42 | 42 | } |
| @@ -139,6 +139,10 @@ function throwIfInvalidModel(useReverseProxy) { | ||
| 139 | 139 | throw new Error('Google AI Studio API key is not set.'); |
| 140 | 140 | } |
| 141 | 141 | |
| 142 | + if (extension_settings.caption.multi_modal_api === 'mistral' && !secret_state[SECRET_KEYS.MISTRALAI] && !useReverseProxy) { | |
| 143 | + throw new Error('Mistral AI API key is not set.'); | |
| 144 | + } | |
| 145 | + | |
| 142 | 146 | if (extension_settings.caption.multimodal_api === 'ollama' && !textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]) { |
| 143 | 147 | throw new Error('Ollama server URL is not set.'); |
| 144 | 148 | } |
| @@ -2490,7 +2490,7 @@ class Message { | ||
| 2490 | 2490 | * @returns {Promise<string>} Compressed image as a Data URL. |
| 2491 | 2491 | */ |
| 2492 | 2492 | async compressImage(image) { |
| 2493 | 2493 | if ([chat_completion_sources.OPENROUTER, chat_completion_sources.MAKERSUITE, chat_completion_sources.MISTRALAI].includes(oai_settings.chat_completion_source)) { |
| 2494 | 2494 | const sizeThreshold = 2 * 1024 * 1024; |
| 2495 | 2495 | const dataSize = image.length * 0.75; |
| 2496 | 2496 | const maxSide = 1024; |
| @@ -4221,6 +4221,8 @@ async function onModelChange() { | ||
| 4221 | 4221 | $('#openai_max_context').attr('max', max_128k); |
| 4222 | 4222 | } else if (oai_settings.mistralai_model.includes('mixtral-8x22b')) { |
| 4223 | 4223 | $('#openai_max_context').attr('max', max_64k); |
| 4224 | + } else if (oai_settings.mistralai_model.includes('pixtral')) { | |
| 4225 | + $('#openai_max_context').attr('max', max_128k); | |
| 4224 | 4226 | } else { |
| 4225 | 4227 | $('#openai_max_context').attr('max', max_32k); |
| 4226 | 4228 | } |
| @@ -4770,6 +4772,8 @@ export function isImageInliningSupported() { | ||
| 4770 | 4772 | 'gpt-4o-mini', |
| 4771 | 4773 | 'chatgpt-4o-latest', |
| 4772 | 4774 | 'yi-vision', |
| 4775 | + 'pixtral-latest', | |
| 4776 | + 'pixtral-12b-2409', | |
| 4773 | 4777 | ]; |
| 4774 | 4778 | |
| 4775 | 4779 | switch (oai_settings.chat_completion_source) { |
| @@ -4785,6 +4789,8 @@ export function isImageInliningSupported() { | ||
| 4785 | 4789 | return true; |
| 4786 | 4790 | case chat_completion_sources.ZEROONEAI: |
| 4787 | 4791 | return visionSupportedModels.some(model => oai_settings.zerooneai_model.includes(model)); |
| 4792 | + case chat_completion_sources.MISTRALAI: | |
| 4793 | + return visionSupportedModels.some(model => oai_settings.mistralai_model.includes(model)); | |
| 4788 | 4794 | default: |
| 4789 | 4795 | return false; |
| 4790 | 4796 | } |
| @@ -51,6 +51,10 @@ router.post('/caption-image', jsonParser, async (request, response) => { | ||
| 51 | 51 | key = readSecret(request.user.directories, SECRET_KEYS.ZEROONEAI); |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | + if (request.body.api === 'mistral') { | |
| 55 | + key = readSecret(request.user.directories, SECRET_KEYS.MISTRALAI); | |
| 56 | + } | |
| 57 | + | |
| 54 | 58 | if (!key && !request.body.reverse_proxy && ['custom', 'ooba', 'koboldcpp', 'vllm'].includes(request.body.api) === false) { |
| 55 | 59 | console.log('No key found for API', request.body.api); |
| 56 | 60 | return response.sendStatus(400); |
| @@ -107,6 +111,10 @@ router.post('/caption-image', jsonParser, async (request, response) => { | ||
| 107 | 111 | apiUrl = 'https://api.01.ai/v1/chat/completions'; |
| 108 | 112 | } |
| 109 | 113 | |
| 114 | + if (request.body.api === 'mistral') { | |
| 115 | + apiUrl = 'https://api.mistral.ai/v1/chat/completions'; | |
| 116 | + } | |
| 117 | + | |
| 110 | 118 | if (request.body.api === 'ooba') { |
| 111 | 119 | apiUrl = `${trimV1(request.body.server_url)}/v1/chat/completions`; |
| 112 | 120 | const imgMessage = body.messages.pop(); |