Add Vertex AI express mode support (#3977) * Add Vertex AI express mode support Split Google AI Studio and Vertex AI * Add support for Vertex AI, including updating default models and related settings, modifying frontend HTML to include Vertex AI options, and adjusting request processing logic in the backend API. * Log API name in the console * Merge sysprompt toggles back * Use Gemma tokenizers for Vertex and LearnLM * AI Studio parity updates * Add link to express mode doc. Also technically it's not a form * Split title * Use array includes * Add support for Google Vertex AI in image captioning feature * Specify caption API name, add to compression list --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -15,6 +15,7 @@ | |||
| 15 | "custom_exclude_body": "", | 15 | "custom_exclude_body": "", |
| 16 | "custom_include_headers": "", | 16 | "custom_include_headers": "", |
| 17 | "google_model": "gemini-pro", | 17 | "google_model": "gemini-pro", |
| 18 | "vertexai_model": "gemini-2.0-flash-001", | ||
| 18 | "temperature": 1, | 19 | "temperature": 1, |
| 19 | "frequency_penalty": 0, | 20 | "frequency_penalty": 0, |
| 20 | "presence_penalty": 0, | 21 | "presence_penalty": 0, |
| @@ -691,7 +691,7 @@ | |||
| 691 | </span> | 691 | </span> |
| 692 | </div> | 692 | </div> |
| 693 | </div> | 693 | </div> |
| 694 | <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai"> | 694 | <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai"> |
| 695 | <div class="range-block-title" data-i18n="Temperature"> | 695 | <div class="range-block-title" data-i18n="Temperature"> |
| 696 | Temperature | 696 | Temperature |
| 697 | </div> | 697 | </div> |
| @@ -730,7 +730,7 @@ | |||
| 730 | </div> | 730 | </div> |
| 731 | </div> | 731 | </div> |
| 732 | </div> | 732 | </div> |
| 733 | <div class="range-block" data-source="claude,openrouter,makersuite,cohere,perplexity"> | 733 | <div class="range-block" data-source="claude,openrouter,makersuite,vertexai,cohere,perplexity"> |
| 734 | <div class="range-block-title" data-i18n="Top K"> | 734 | <div class="range-block-title" data-i18n="Top K"> |
| 735 | Top K | 735 | Top K |
| 736 | </div> | 736 | </div> |
| @@ -743,7 +743,7 @@ | |||
| 743 | </div> | 743 | </div> |
| 744 | </div> | 744 | </div> |
| 745 | </div> | 745 | </div> |
| 746 | <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai"> | 746 | <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai"> |
| 747 | <div class="range-block-title" data-i18n="Top P"> | 747 | <div class="range-block-title" data-i18n="Top P"> |
| 748 | Top P | 748 | Top P |
| 749 | </div> | 749 | </div> |
| @@ -1969,7 +1969,7 @@ | |||
| 1969 | </span> | 1969 | </span> |
| 1970 | </div> | 1970 | </div> |
| 1971 | </div> | 1971 | </div> |
| 1972 | <div class="range-block" data-source="makersuite,openrouter,claude"> | 1972 | <div class="range-block" data-source="makersuite,vertexai,openrouter,claude"> |
| 1973 | <label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand"> | 1973 | <label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand"> |
| 1974 | <input id="openai_enable_web_search" type="checkbox" /> | 1974 | <input id="openai_enable_web_search" type="checkbox" /> |
| 1975 | <span data-i18n="Enable web search">Enable web search</span> | 1975 | <span data-i18n="Enable web search">Enable web search</span> |
| @@ -1983,7 +1983,7 @@ | |||
| 1983 | </b> | 1983 | </b> |
| 1984 | </div> | 1984 | </div> |
| 1985 | </div> | 1985 | </div> |
| 1986 | <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite,ai21,xai,pollinations"> | 1986 | <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite,vertexai,ai21,xai,pollinations"> |
| 1987 | <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand"> | 1987 | <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand"> |
| 1988 | <input id="openai_function_calling" type="checkbox" /> | 1988 | <input id="openai_function_calling" type="checkbox" /> |
| 1989 | <span data-i18n="Enable function calling">Enable function calling</span> | 1989 | <span data-i18n="Enable function calling">Enable function calling</span> |
| @@ -1993,7 +1993,7 @@ | |||
| 1993 | <span data-i18n="enable_functions_desc_3">Can be utilized by various extensions to provide additional functionality.</span> | 1993 | <span data-i18n="enable_functions_desc_3">Can be utilized by various extensions to provide additional functionality.</span> |
| 1994 | </div> | 1994 | </div> |
| 1995 | </div> | 1995 | </div> |
| 1996 | <div class="range-block" data-source="openai,openrouter,mistralai,makersuite,claude,custom,01ai,xai,pollinations"> | 1996 | <div class="range-block" data-source="openai,openrouter,mistralai,makersuite,vertexai,claude,custom,01ai,xai,pollinations"> |
| 1997 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> | 1997 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> |
| 1998 | <input id="openai_image_inlining" type="checkbox" /> | 1998 | <input id="openai_image_inlining" type="checkbox" /> |
| 1999 | <span data-i18n="Send inline images">Send inline images</span> | 1999 | <span data-i18n="Send inline images">Send inline images</span> |
| @@ -2018,7 +2018,7 @@ | |||
| 2018 | </div> | 2018 | </div> |
| 2019 | </div> | 2019 | </div> |
| 2020 | </div> | 2020 | </div> |
| 2021 | <div class="range-block" data-source="makersuite"> | 2021 | <div class="range-block" data-source="makersuite,vertexai"> |
| 2022 | <label for="openai_request_images" class="checkbox_label widthFreeExpand"> | 2022 | <label for="openai_request_images" class="checkbox_label widthFreeExpand"> |
| 2023 | <input id="openai_request_images" type="checkbox" /> | 2023 | <input id="openai_request_images" type="checkbox" /> |
| 2024 | <span> | 2024 | <span> |
| @@ -2030,12 +2030,12 @@ | |||
| 2030 | <span data-i18n="Allows the model to return image attachments."> | 2030 | <span data-i18n="Allows the model to return image attachments."> |
| 2031 | Allows the model to return image attachments. | 2031 | Allows the model to return image attachments. |
| 2032 | </span> | 2032 | </span> |
| 2033 | <em data-source="makersuite" data-i18n="Request inline images_desc_2"> | 2033 | <em data-source="makersuite,vertexai" data-i18n="Request inline images_desc_2"> |
| 2034 | Incompatible with the following features: function calling, web search, system prompt. | 2034 | Incompatible with the following features: function calling, web search, system prompt. |
| 2035 | </em> | 2035 | </em> |
| 2036 | </div> | 2036 | </div> |
| 2037 | </div> | 2037 | </div> |
| 2038 | <div class="range-block" data-source="makersuite"> | 2038 | <div class="range-block" data-source="makersuite,vertexai"> |
| 2039 | <label for="use_makersuite_sysprompt" class="checkbox_label widthFreeExpand"> | 2039 | <label for="use_makersuite_sysprompt" class="checkbox_label widthFreeExpand"> |
| 2040 | <input id="use_makersuite_sysprompt" type="checkbox" /> | 2040 | <input id="use_makersuite_sysprompt" type="checkbox" /> |
| 2041 | <span> | 2041 | <span> |
| @@ -2060,12 +2060,12 @@ | |||
| 2060 | </span> | 2060 | </span> |
| 2061 | </div> | 2061 | </div> |
| 2062 | </div> | 2062 | </div> |
| 2063 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,openrouter,pollinations"> | 2063 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,vertexai,openrouter,pollinations"> |
| 2064 | <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models."> | 2064 | <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models."> |
| 2065 | <label for="openai_reasoning_effort"> | 2065 | <label for="openai_reasoning_effort"> |
| 2066 | <span data-i18n="Reasoning Effort">Reasoning Effort</span> | 2066 | <span data-i18n="Reasoning Effort">Reasoning Effort</span> |
| 2067 | <i data-source="openai,custom,xai,openrouter" class="opacity50p fa-solid fa-circle-info" title="OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level." data-i18n="[title]OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level."></i> | 2067 | <i data-source="openai,custom,xai,openrouter" class="opacity50p fa-solid fa-circle-info" title="OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level." data-i18n="[title]OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level."></i> |
| 2068 | <i data-source="claude,makersuite" class="opacity50p fa-solid fa-circle-info" title="Allocates a portion of the response length for thinking (low: 10%, medium: 25%, high: 50%). Other options are model-dependent." data-i18n="[title]Allocates a portion of the response length for thinking (low: 10%, medium: 25%, high: 50%). Other options are model-dependent."></i> | 2068 | <i data-source="claude,makersuite,vertexai" class="opacity50p fa-solid fa-circle-info" title="Allocates a portion of the response length for thinking (low: 10%, medium: 25%, high: 50%). Other options are model-dependent." data-i18n="[title]Allocates a portion of the response length for thinking (low: 10%, medium: 25%, high: 50%). Other options are model-dependent."></i> |
| 2069 | </label> | 2069 | </label> |
| 2070 | <select id="openai_reasoning_effort"> | 2070 | <select id="openai_reasoning_effort"> |
| 2071 | <option data-i18n="openai_reasoning_effort_auto" value="auto">Auto</option> | 2071 | <option data-i18n="openai_reasoning_effort_auto" value="auto">Auto</option> |
| @@ -2769,6 +2769,7 @@ | |||
| 2769 | <option value="deepseek">DeepSeek</option> | 2769 | <option value="deepseek">DeepSeek</option> |
| 2770 | <option value="groq">Groq</option> | 2770 | <option value="groq">Groq</option> |
| 2771 | <option value="makersuite">Google AI Studio</option> | 2771 | <option value="makersuite">Google AI Studio</option> |
| 2772 | <option value="vertexai">Google Vertex AI (Express mode)</option> | ||
| 2772 | <option value="mistralai">MistralAI</option> | 2773 | <option value="mistralai">MistralAI</option> |
| 2773 | <option value="nanogpt">NanoGPT</option> | 2774 | <option value="nanogpt">NanoGPT</option> |
| 2774 | <option value="openrouter">OpenRouter</option> | 2775 | <option value="openrouter">OpenRouter</option> |
| @@ -2779,7 +2780,7 @@ | |||
| 2779 | <option value="xai">xAI (Grok)</option> | 2780 | <option value="xai">xAI (Grok)</option> |
| 2780 | </optgroup> | 2781 | </optgroup> |
| 2781 | </select> | 2782 | </select> |
| 2782 | <div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,deepseek,xai"> | 2783 | <div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,vertexai,deepseek,xai"> |
| 2783 | <div class="inline-drawer-toggle inline-drawer-header"> | 2784 | <div class="inline-drawer-toggle inline-drawer-header"> |
| 2784 | <b data-i18n="Reverse Proxy">Reverse Proxy</b> | 2785 | <b data-i18n="Reverse Proxy">Reverse Proxy</b> |
| 2785 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | 2786 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> |
| @@ -2843,7 +2844,7 @@ | |||
| 2843 | </div> | 2844 | </div> |
| 2844 | </div> | 2845 | </div> |
| 2845 | </div> | 2846 | </div> |
| 2846 | <div id="ReverseProxyWarningMessage" data-source="openai,claude,mistralai,makersuite,deepseek,xai"> | 2847 | <div id="ReverseProxyWarningMessage" data-source="openai,claude,mistralai,makersuite,vertexai,deepseek,xai"> |
| 2847 | <div class="reverse_proxy_warning"> | 2848 | <div class="reverse_proxy_warning"> |
| 2848 | <b> | 2849 | <b> |
| 2849 | <div data-i18n="Using a proxy that you're not running yourself is a risk to your data privacy."> | 2850 | <div data-i18n="Using a proxy that you're not running yourself is a risk to your data privacy."> |
| @@ -3209,6 +3210,38 @@ | |||
| 3209 | </select> | 3210 | </select> |
| 3210 | </div> | 3211 | </div> |
| 3211 | </form> | 3212 | </form> |
| 3213 | <div id="vertexai_form" data-source="vertexai"> | ||
| 3214 | <h4> | ||
| 3215 | <span data-i18n="Google Vertex AI API Key"> | ||
| 3216 | Google Vertex AI API Key | ||
| 3217 | </span> | ||
| 3218 | <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/start/express-mode/overview" data-i18n="(Express mode keys only)" target="_blank" rel="noopener noreferrer"> | ||
| 3219 | (Express mode keys only) | ||
| 3220 | </a> | ||
| 3221 | </h4> | ||
| 3222 | <div class="flex-container"> | ||
| 3223 | <input id="api_key_vertexai" name="api_key_vertexai" class="text_pole flex1" value="" type="text" autocomplete="off"> | ||
| 3224 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_vertexai"></div> | ||
| 3225 | </div> | ||
| 3226 | <div data-for="api_key_vertexai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | ||
| 3227 | For privacy reasons, your API key will be hidden after you reload the page. | ||
| 3228 | </div> | ||
| 3229 | <div> | ||
| 3230 | <h4 data-i18n="Google Model">Google Model</h4> | ||
| 3231 | <select id="model_vertexai_select"> | ||
| 3232 | <optgroup label="Gemini 2.5"> | ||
| 3233 | <option value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> | ||
| 3234 | <option value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> | ||
| 3235 | <option value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> | ||
| 3236 | <option value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | ||
| 3237 | </optgroup> | ||
| 3238 | <optgroup label="Gemini 2.0"> | ||
| 3239 | <option value="gemini-2.0-flash-001">gemini-2.0-flash-001</option> | ||
| 3240 | <option value="gemini-2.0-flash-lite-001">gemini-2.0-flash-lite-001</option> | ||
| 3241 | </optgroup> | ||
| 3242 | </select> | ||
| 3243 | </div> | ||
| 3244 | </div> | ||
| 3212 | <form id="mistralai_form" data-source="mistralai" action="javascript:void(null);" method="post" enctype="multipart/form-data"> | 3245 | <form id="mistralai_form" data-source="mistralai" action="javascript:void(null);" method="post" enctype="multipart/form-data"> |
| 3213 | <h4 data-i18n="MistralAI API Key">MistralAI API Key</h4> | 3246 | <h4 data-i18n="MistralAI API Key">MistralAI API Key</h4> |
| 3214 | <div class="flex-container"> | 3247 | <div class="flex-container"> |
| @@ -5941,6 +5941,7 @@ function extractImageFromData(data, { mainApi = null, chatCompletionSource = nul | |||
| 5941 | switch (mainApi ?? main_api) { | 5941 | switch (mainApi ?? main_api) { |
| 5942 | case 'openai': { | 5942 | case 'openai': { |
| 5943 | switch (chatCompletionSource ?? oai_settings.chat_completion_source) { | 5943 | switch (chatCompletionSource ?? oai_settings.chat_completion_source) { |
| 5944 | case chat_completion_sources.VERTEXAI: | ||
| 5944 | case chat_completion_sources.MAKERSUITE: { | 5945 | case chat_completion_sources.MAKERSUITE: { |
| 5945 | const inlineData = data?.responseContent?.parts?.find(x => x.inlineData)?.inlineData; | 5946 | const inlineData = data?.responseContent?.parts?.find(x => x.inlineData)?.inlineData; |
| 5946 | if (inlineData) { | 5947 | if (inlineData) { |
| @@ -402,6 +402,7 @@ function RA_autoconnect(PrevApi) { | |||
| 402 | || (secret_state[SECRET_KEYS.OPENROUTER] && oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER) | 402 | || (secret_state[SECRET_KEYS.OPENROUTER] && oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER) |
| 403 | || (secret_state[SECRET_KEYS.AI21] && oai_settings.chat_completion_source == chat_completion_sources.AI21) | 403 | || (secret_state[SECRET_KEYS.AI21] && oai_settings.chat_completion_source == chat_completion_sources.AI21) |
| 404 | || (secret_state[SECRET_KEYS.MAKERSUITE] && oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) | 404 | || (secret_state[SECRET_KEYS.MAKERSUITE] && oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) |
| 405 | || (secret_state[SECRET_KEYS.VERTEXAI] && oai_settings.chat_completion_source == chat_completion_sources.VERTEXAI) | ||
| 405 | || (secret_state[SECRET_KEYS.MISTRALAI] && oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) | 406 | || (secret_state[SECRET_KEYS.MISTRALAI] && oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) |
| 406 | || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE) | 407 | || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE) |
| 407 | || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) | 408 | || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) |
| @@ -414,6 +414,7 @@ jQuery(async function () { | |||
| 414 | 'openai': SECRET_KEYS.OPENAI, | 414 | 'openai': SECRET_KEYS.OPENAI, |
| 415 | 'mistral': SECRET_KEYS.MISTRALAI, | 415 | 'mistral': SECRET_KEYS.MISTRALAI, |
| 416 | 'google': SECRET_KEYS.MAKERSUITE, | 416 | 'google': SECRET_KEYS.MAKERSUITE, |
| 417 | 'vertexai': SECRET_KEYS.VERTEXAI, | ||
| 417 | 'anthropic': SECRET_KEYS.CLAUDE, | 418 | 'anthropic': SECRET_KEYS.CLAUDE, |
| 418 | }; | 419 | }; |
| 419 | 420 | ||
| @@ -22,6 +22,7 @@ | |||
| 22 | <option value="cohere">Cohere</option> | 22 | <option value="cohere">Cohere</option> |
| 23 | <option value="custom" data-i18n="Custom (OpenAI-compatible)">Custom (OpenAI-compatible)</option> | 23 | <option value="custom" data-i18n="Custom (OpenAI-compatible)">Custom (OpenAI-compatible)</option> |
| 24 | <option value="google">Google AI Studio</option> | 24 | <option value="google">Google AI Studio</option> |
| 25 | <option value="vertexai">Google Vertex AI</option> | ||
| 25 | <option value="groq">Groq</option> | 26 | <option value="groq">Groq</option> |
| 26 | <option value="koboldcpp">KoboldCpp</option> | 27 | <option value="koboldcpp">KoboldCpp</option> |
| 27 | <option value="llamacpp">llama.cpp</option> | 28 | <option value="llamacpp">llama.cpp</option> |
| @@ -111,6 +112,12 @@ | |||
| 111 | <option data-type="google" value="gemini-1.5-flash-8b-exp-0827">gemini-1.5-flash-8b-exp-0827</option> | 112 | <option data-type="google" value="gemini-1.5-flash-8b-exp-0827">gemini-1.5-flash-8b-exp-0827</option> |
| 112 | <option data-type="google" value="learnlm-2.0-flash-experimental">learnlm-2.0-flash-experimental</option> | 113 | <option data-type="google" value="learnlm-2.0-flash-experimental">learnlm-2.0-flash-experimental</option> |
| 113 | <option data-type="google" value="learnlm-1.5-pro-experimental">learnlm-1.5-pro-experimental</option> | 114 | <option data-type="google" value="learnlm-1.5-pro-experimental">learnlm-1.5-pro-experimental</option> |
| 115 | <option data-type="vertexai" value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> | ||
| 116 | <option data-type="vertexai" value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> | ||
| 117 | <option data-type="vertexai" value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> | ||
| 118 | <option data-type="vertexai" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | ||
| 119 | <option data-type="vertexai" value="gemini-2.0-flash-001">gemini-2.0-flash-001</option> | ||
| 120 | <option data-type="vertexai" value="gemini-2.0-flash-lite-001">gemini-2.0-flash-lite-001</option> | ||
| 114 | <option data-type="groq" value="llama-3.2-11b-vision-preview">llama-3.2-11b-vision-preview</option> | 121 | <option data-type="groq" value="llama-3.2-11b-vision-preview">llama-3.2-11b-vision-preview</option> |
| 115 | <option data-type="groq" value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview</option> | 122 | <option data-type="groq" value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview</option> |
| 116 | <option data-type="groq" value="llava-v1.5-7b-4096-preview">llava-v1.5-7b-4096-preview</option> | 123 | <option data-type="groq" value="llava-v1.5-7b-4096-preview">llava-v1.5-7b-4096-preview</option> |
| @@ -170,7 +177,7 @@ | |||
| 170 | <div data-type="ollama"> | 177 | <div data-type="ollama"> |
| 171 | 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>. | 178 | 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>. |
| 172 | </div> | 179 | </div> |
| 173 | <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."> | 180 | <label data-type="openai,anthropic,google,vertexai,mistral" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid."> |
| 174 | <input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox"> | 181 | <input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox"> |
| 175 | <span data-i18n="Allow reverse proxy">Allow reverse proxy</span> | 182 | <span data-i18n="Allow reverse proxy">Allow reverse proxy</span> |
| 176 | </label> | 183 | </label> |
| @@ -15,7 +15,7 @@ import { createThumbnail, isValidUrl } from '../utils.js'; | |||
| 15 | */ | 15 | */ |
| 16 | export async function getMultimodalCaption(base64Img, prompt) { | 16 | export async function getMultimodalCaption(base64Img, prompt) { |
| 17 | const useReverseProxy = | 17 | const useReverseProxy = |
| 18 | (['openai', 'anthropic', 'google', 'mistral'].includes(extension_settings.caption.multimodal_api)) | 18 | (['openai', 'anthropic', 'google', 'mistral', 'vertexai'].includes(extension_settings.caption.multimodal_api)) |
| 19 | && extension_settings.caption.allow_reverse_proxy | 19 | && extension_settings.caption.allow_reverse_proxy |
| 20 | && oai_settings.reverse_proxy | 20 | && oai_settings.reverse_proxy |
| 21 | && isValidUrl(oai_settings.reverse_proxy); | 21 | && isValidUrl(oai_settings.reverse_proxy); |
| @@ -38,7 +38,8 @@ export async function getMultimodalCaption(base64Img, prompt) { | |||
| 38 | const isVllm = extension_settings.caption.multimodal_api === 'vllm'; | 38 | const isVllm = extension_settings.caption.multimodal_api === 'vllm'; |
| 39 | const base64Bytes = base64Img.length * 0.75; | 39 | const base64Bytes = base64Img.length * 0.75; |
| 40 | const compressionLimit = 2 * 1024 * 1024; | 40 | const compressionLimit = 2 * 1024 * 1024; |
| 41 | if ((['google', 'openrouter', 'mistral', 'groq'].includes(extension_settings.caption.multimodal_api) && base64Bytes > compressionLimit) || isOoba || isKoboldCpp) { | 41 | const thumbnailNeeded = ['google', 'openrouter', 'mistral', 'groq', 'vertexai'].includes(extension_settings.caption.multimodal_api); |
| 42 | if ((thumbnailNeeded && base64Bytes > compressionLimit) || isOoba || isKoboldCpp) { | ||
| 42 | const maxSide = 1024; | 43 | const maxSide = 1024; |
| 43 | base64Img = await createThumbnail(base64Img, maxSide, maxSide, 'image/jpeg'); | 44 | base64Img = await createThumbnail(base64Img, maxSide, maxSide, 'image/jpeg'); |
| 44 | } | 45 | } |
| @@ -94,6 +95,7 @@ export async function getMultimodalCaption(base64Img, prompt) { | |||
| 94 | function getEndpointUrl() { | 95 | function getEndpointUrl() { |
| 95 | switch (extension_settings.caption.multimodal_api) { | 96 | switch (extension_settings.caption.multimodal_api) { |
| 96 | case 'google': | 97 | case 'google': |
| 98 | case 'vertexai': | ||
| 97 | return '/api/google/caption-image'; | 99 | return '/api/google/caption-image'; |
| 98 | case 'anthropic': | 100 | case 'anthropic': |
| 99 | return '/api/anthropic/caption-image'; | 101 | return '/api/anthropic/caption-image'; |
| @@ -143,6 +145,10 @@ function throwIfInvalidModel(useReverseProxy) { | |||
| 143 | throw new Error('Google AI Studio API key is not set.'); | 145 | throw new Error('Google AI Studio API key is not set.'); |
| 144 | } | 146 | } |
| 145 | 147 | ||
| 148 | if (extension_settings.caption.multimodal_api === 'vertexai' && !secret_state[SECRET_KEYS.VERTEXAI] && !useReverseProxy) { | ||
| 149 | throw new Error('Google Vertex AI API key is not set.'); | ||
| 150 | } | ||
| 151 | |||
| 146 | if (extension_settings.caption.multimodal_api === 'mistral' && !secret_state[SECRET_KEYS.MISTRALAI] && !useReverseProxy) { | 152 | if (extension_settings.caption.multimodal_api === 'mistral' && !secret_state[SECRET_KEYS.MISTRALAI] && !useReverseProxy) { |
| 147 | throw new Error('Mistral AI API key is not set.'); | 153 | throw new Error('Mistral AI API key is not set.'); |
| 148 | } | 154 | } |
| @@ -176,6 +176,7 @@ export const chat_completion_sources = { | |||
| 176 | OPENROUTER: 'openrouter', | 176 | OPENROUTER: 'openrouter', |
| 177 | AI21: 'ai21', | 177 | AI21: 'ai21', |
| 178 | MAKERSUITE: 'makersuite', | 178 | MAKERSUITE: 'makersuite', |
| 179 | VERTEXAI: 'vertexai', | ||
| 179 | MISTRALAI: 'mistralai', | 180 | MISTRALAI: 'mistralai', |
| 180 | CUSTOM: 'custom', | 181 | CUSTOM: 'custom', |
| 181 | COHERE: 'cohere', | 182 | COHERE: 'cohere', |
| @@ -277,6 +278,7 @@ export const settingsToUpdate = { | |||
| 277 | custom_include_headers: ['#custom_include_headers', 'custom_include_headers', false, true], | 278 | custom_include_headers: ['#custom_include_headers', 'custom_include_headers', false, true], |
| 278 | custom_prompt_post_processing: ['#custom_prompt_post_processing', 'custom_prompt_post_processing', false, true], | 279 | custom_prompt_post_processing: ['#custom_prompt_post_processing', 'custom_prompt_post_processing', false, true], |
| 279 | google_model: ['#model_google_select', 'google_model', false, true], | 280 | google_model: ['#model_google_select', 'google_model', false, true], |
| 281 | vertexai_model: ['#model_vertexai_select', 'vertexai_model', false, true], | ||
| 280 | openai_max_context: ['#openai_max_context', 'openai_max_context', false, false], | 282 | openai_max_context: ['#openai_max_context', 'openai_max_context', false, false], |
| 281 | openai_max_tokens: ['#openai_max_tokens', 'openai_max_tokens', false, false], | 283 | openai_max_tokens: ['#openai_max_tokens', 'openai_max_tokens', false, false], |
| 282 | wrap_in_quotes: ['#wrap_in_quotes', 'wrap_in_quotes', true, false], | 284 | wrap_in_quotes: ['#wrap_in_quotes', 'wrap_in_quotes', true, false], |
| @@ -350,6 +352,7 @@ const default_settings = { | |||
| 350 | openai_model: 'gpt-4-turbo', | 352 | openai_model: 'gpt-4-turbo', |
| 351 | claude_model: 'claude-3-5-sonnet-20240620', | 353 | claude_model: 'claude-3-5-sonnet-20240620', |
| 352 | google_model: 'gemini-1.5-pro', | 354 | google_model: 'gemini-1.5-pro', |
| 355 | vertexai_model: 'gemini-2.0-flash-001', | ||
| 353 | ai21_model: 'jamba-1.6-large', | 356 | ai21_model: 'jamba-1.6-large', |
| 354 | mistralai_model: 'mistral-large-latest', | 357 | mistralai_model: 'mistral-large-latest', |
| 355 | cohere_model: 'command-r-plus', | 358 | cohere_model: 'command-r-plus', |
| @@ -433,6 +436,7 @@ const oai_settings = { | |||
| 433 | openai_model: 'gpt-4-turbo', | 436 | openai_model: 'gpt-4-turbo', |
| 434 | claude_model: 'claude-3-5-sonnet-20240620', | 437 | claude_model: 'claude-3-5-sonnet-20240620', |
| 435 | google_model: 'gemini-1.5-pro', | 438 | google_model: 'gemini-1.5-pro', |
| 439 | vertexai_model: 'gemini-2.0-flash-001', | ||
| 436 | ai21_model: 'jamba-1.6-large', | 440 | ai21_model: 'jamba-1.6-large', |
| 437 | mistralai_model: 'mistral-large-latest', | 441 | mistralai_model: 'mistral-large-latest', |
| 438 | cohere_model: 'command-r-plus', | 442 | cohere_model: 'command-r-plus', |
| @@ -1666,6 +1670,8 @@ export function getChatCompletionModel(source = null) { | |||
| 1666 | return ''; | 1670 | return ''; |
| 1667 | case chat_completion_sources.MAKERSUITE: | 1671 | case chat_completion_sources.MAKERSUITE: |
| 1668 | return oai_settings.google_model; | 1672 | return oai_settings.google_model; |
| 1673 | case chat_completion_sources.VERTEXAI: | ||
| 1674 | return oai_settings.vertexai_model; | ||
| 1669 | case chat_completion_sources.OPENROUTER: | 1675 | case chat_completion_sources.OPENROUTER: |
| 1670 | return oai_settings.openrouter_model !== openrouter_website_model ? oai_settings.openrouter_model : null; | 1676 | return oai_settings.openrouter_model !== openrouter_website_model ? oai_settings.openrouter_model : null; |
| 1671 | case chat_completion_sources.AI21: | 1677 | case chat_completion_sources.AI21: |
| @@ -2048,6 +2054,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2048 | const isOpenRouter = oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER; | 2054 | const isOpenRouter = oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER; |
| 2049 | const isScale = oai_settings.chat_completion_source == chat_completion_sources.SCALE; | 2055 | const isScale = oai_settings.chat_completion_source == chat_completion_sources.SCALE; |
| 2050 | const isGoogle = oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE; | 2056 | const isGoogle = oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE; |
| 2057 | const isVertexAI = oai_settings.chat_completion_source == chat_completion_sources.VERTEXAI; | ||
| 2051 | const isOAI = oai_settings.chat_completion_source == chat_completion_sources.OPENAI; | 2058 | const isOAI = oai_settings.chat_completion_source == chat_completion_sources.OPENAI; |
| 2052 | const isMistral = oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI; | 2059 | const isMistral = oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI; |
| 2053 | const isCustom = oai_settings.chat_completion_source == chat_completion_sources.CUSTOM; | 2060 | const isCustom = oai_settings.chat_completion_source == chat_completion_sources.CUSTOM; |
| @@ -2123,8 +2130,8 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2123 | delete generate_data.stop; | 2130 | delete generate_data.stop; |
| 2124 | } | 2131 | } |
| 2125 | 2132 | ||
| 2126 | // Proxy is only supported for Claude, OpenAI, Mistral, and Google MakerSuite | 2133 | // Proxy is only supported for Claude, OpenAI, Mistral, Google MakerSuite, and Vertex AI |
| 2127 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.DEEPSEEK, chat_completion_sources.XAI].includes(oai_settings.chat_completion_source)) { | 2134 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.VERTEXAI, chat_completion_sources.DEEPSEEK, chat_completion_sources.XAI].includes(oai_settings.chat_completion_source)) { |
| 2128 | await validateReverseProxy(); | 2135 | await validateReverseProxy(); |
| 2129 | generate_data['reverse_proxy'] = oai_settings.reverse_proxy; | 2136 | generate_data['reverse_proxy'] = oai_settings.reverse_proxy; |
| 2130 | generate_data['proxy_password'] = oai_settings.proxy_password; | 2137 | generate_data['proxy_password'] = oai_settings.proxy_password; |
| @@ -2175,7 +2182,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2175 | generate_data['api_url_scale'] = oai_settings.api_url_scale; | 2182 | generate_data['api_url_scale'] = oai_settings.api_url_scale; |
| 2176 | } | 2183 | } |
| 2177 | 2184 | ||
| 2178 | if (isGoogle) { | 2185 | if (isGoogle || isVertexAI) { |
| 2179 | const stopStringsLimit = 5; | 2186 | const stopStringsLimit = 5; |
| 2180 | generate_data['top_k'] = Number(oai_settings.top_k_openai); | 2187 | generate_data['top_k'] = Number(oai_settings.top_k_openai); |
| 2181 | generate_data['stop'] = getCustomStoppingStrings(stopStringsLimit).slice(0, stopStringsLimit).filter(x => x.length >= 1 && x.length <= 16); | 2188 | generate_data['stop'] = getCustomStoppingStrings(stopStringsLimit).slice(0, stopStringsLimit).filter(x => x.length >= 1 && x.length <= 16); |
| @@ -2382,7 +2389,7 @@ export function getStreamingReply(data, state, { chatCompletionSource = null, ov | |||
| 2382 | state.reasoning += data?.delta?.thinking || ''; | 2389 | state.reasoning += data?.delta?.thinking || ''; |
| 2383 | } | 2390 | } |
| 2384 | return data?.delta?.text || ''; | 2391 | return data?.delta?.text || ''; |
| 2385 | } else if (chat_completion_source === chat_completion_sources.MAKERSUITE) { | 2392 | } else if ([chat_completion_sources.MAKERSUITE, chat_completion_sources.VERTEXAI].includes(chat_completion_source)) { |
| 2386 | const inlineData = data?.candidates?.[0]?.content?.parts?.find(x => x.inlineData)?.inlineData; | 2393 | const inlineData = data?.candidates?.[0]?.content?.parts?.find(x => x.inlineData)?.inlineData; |
| 2387 | if (inlineData) { | 2394 | if (inlineData) { |
| 2388 | state.image = `data:${inlineData.mimeType};base64,${inlineData.data}`; | 2395 | state.image = `data:${inlineData.mimeType};base64,${inlineData.data}`; |
| @@ -2772,7 +2779,13 @@ class Message { | |||
| 2772 | * @returns {Promise<string>} Compressed image as a Data URL. | 2779 | * @returns {Promise<string>} Compressed image as a Data URL. |
| 2773 | */ | 2780 | */ |
| 2774 | async compressImage(image) { | 2781 | async compressImage(image) { |
| 2775 | if ([chat_completion_sources.OPENROUTER, chat_completion_sources.MAKERSUITE, chat_completion_sources.MISTRALAI].includes(oai_settings.chat_completion_source)) { | 2782 | const compressImageSources = [ |
| 2783 | chat_completion_sources.OPENROUTER, | ||
| 2784 | chat_completion_sources.MAKERSUITE, | ||
| 2785 | chat_completion_sources.MISTRALAI, | ||
| 2786 | chat_completion_sources.VERTEXAI, | ||
| 2787 | ]; | ||
| 2788 | if (compressImageSources.includes(oai_settings.chat_completion_source)) { | ||
| 2776 | const sizeThreshold = 2 * 1024 * 1024; | 2789 | const sizeThreshold = 2 * 1024 * 1024; |
| 2777 | const dataSize = image.length * 0.75; | 2790 | const dataSize = image.length * 0.75; |
| 2778 | const maxSide = 1024; | 2791 | const maxSide = 1024; |
| @@ -3368,6 +3381,7 @@ function loadOpenAISettings(data, settings) { | |||
| 3368 | oai_settings.custom_include_headers = settings.custom_include_headers ?? default_settings.custom_include_headers; | 3381 | oai_settings.custom_include_headers = settings.custom_include_headers ?? default_settings.custom_include_headers; |
| 3369 | oai_settings.custom_prompt_post_processing = settings.custom_prompt_post_processing ?? default_settings.custom_prompt_post_processing; | 3382 | oai_settings.custom_prompt_post_processing = settings.custom_prompt_post_processing ?? default_settings.custom_prompt_post_processing; |
| 3370 | oai_settings.google_model = settings.google_model ?? default_settings.google_model; | 3383 | oai_settings.google_model = settings.google_model ?? default_settings.google_model; |
| 3384 | oai_settings.vertexai_model = settings.vertexai_model ?? default_settings.vertexai_model; | ||
| 3371 | oai_settings.chat_completion_source = settings.chat_completion_source ?? default_settings.chat_completion_source; | 3385 | oai_settings.chat_completion_source = settings.chat_completion_source ?? default_settings.chat_completion_source; |
| 3372 | oai_settings.api_url_scale = settings.api_url_scale ?? default_settings.api_url_scale; | 3386 | oai_settings.api_url_scale = settings.api_url_scale ?? default_settings.api_url_scale; |
| 3373 | oai_settings.show_external_models = settings.show_external_models ?? default_settings.show_external_models; | 3387 | oai_settings.show_external_models = settings.show_external_models ?? default_settings.show_external_models; |
| @@ -3432,6 +3446,8 @@ function loadOpenAISettings(data, settings) { | |||
| 3432 | $(`#model_windowai_select option[value="${oai_settings.windowai_model}"`).prop('selected', true); | 3446 | $(`#model_windowai_select option[value="${oai_settings.windowai_model}"`).prop('selected', true); |
| 3433 | $('#model_google_select').val(oai_settings.google_model); | 3447 | $('#model_google_select').val(oai_settings.google_model); |
| 3434 | $(`#model_google_select option[value="${oai_settings.google_model}"`).prop('selected', true); | 3448 | $(`#model_google_select option[value="${oai_settings.google_model}"`).prop('selected', true); |
| 3449 | $('#model_vertexai_select').val(oai_settings.vertexai_model); | ||
| 3450 | $(`#model_vertexai_select option[value="${oai_settings.vertexai_model}"`).prop('selected', true); | ||
| 3435 | $('#model_ai21_select').val(oai_settings.ai21_model); | 3451 | $('#model_ai21_select').val(oai_settings.ai21_model); |
| 3436 | $(`#model_ai21_select option[value="${oai_settings.ai21_model}"`).prop('selected', true); | 3452 | $(`#model_ai21_select option[value="${oai_settings.ai21_model}"`).prop('selected', true); |
| 3437 | $('#model_mistralai_select').val(oai_settings.mistralai_model); | 3453 | $('#model_mistralai_select').val(oai_settings.mistralai_model); |
| @@ -3627,6 +3643,7 @@ async function getStatusOpen() { | |||
| 3627 | chat_completion_sources.CLAUDE, | 3643 | chat_completion_sources.CLAUDE, |
| 3628 | chat_completion_sources.AI21, | 3644 | chat_completion_sources.AI21, |
| 3629 | chat_completion_sources.MAKERSUITE, | 3645 | chat_completion_sources.MAKERSUITE, |
| 3646 | chat_completion_sources.VERTEXAI, | ||
| 3630 | chat_completion_sources.PERPLEXITY, | 3647 | chat_completion_sources.PERPLEXITY, |
| 3631 | chat_completion_sources.GROQ, | 3648 | chat_completion_sources.GROQ, |
| 3632 | ]; | 3649 | ]; |
| @@ -3648,7 +3665,16 @@ async function getStatusOpen() { | |||
| 3648 | chat_completion_source: oai_settings.chat_completion_source, | 3665 | chat_completion_source: oai_settings.chat_completion_source, |
| 3649 | }; | 3666 | }; |
| 3650 | 3667 | ||
| 3651 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.DEEPSEEK, chat_completion_sources.XAI].includes(oai_settings.chat_completion_source)) { | 3668 | const validateProxySources = [ |
| 3669 | chat_completion_sources.CLAUDE, | ||
| 3670 | chat_completion_sources.OPENAI, | ||
| 3671 | chat_completion_sources.MISTRALAI, | ||
| 3672 | chat_completion_sources.MAKERSUITE, | ||
| 3673 | chat_completion_sources.VERTEXAI, | ||
| 3674 | chat_completion_sources.DEEPSEEK, | ||
| 3675 | chat_completion_sources.XAI, | ||
| 3676 | ]; | ||
| 3677 | if (oai_settings.reverse_proxy && validateProxySources.includes(oai_settings.chat_completion_source)) { | ||
| 3652 | await validateReverseProxy(); | 3678 | await validateReverseProxy(); |
| 3653 | } | 3679 | } |
| 3654 | 3680 | ||
| @@ -3740,6 +3766,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { | |||
| 3740 | custom_include_headers: settings.custom_include_headers, | 3766 | custom_include_headers: settings.custom_include_headers, |
| 3741 | custom_prompt_post_processing: settings.custom_prompt_post_processing, | 3767 | custom_prompt_post_processing: settings.custom_prompt_post_processing, |
| 3742 | google_model: settings.google_model, | 3768 | google_model: settings.google_model, |
| 3769 | vertexai_model: settings.vertexai_model, | ||
| 3743 | temperature: settings.temp_openai, | 3770 | temperature: settings.temp_openai, |
| 3744 | frequency_penalty: settings.freq_pen_openai, | 3771 | frequency_penalty: settings.freq_pen_openai, |
| 3745 | presence_penalty: settings.pres_pen_openai, | 3772 | presence_penalty: settings.pres_pen_openai, |
| @@ -4495,6 +4522,11 @@ async function onModelChange() { | |||
| 4495 | oai_settings.google_model = value; | 4522 | oai_settings.google_model = value; |
| 4496 | } | 4523 | } |
| 4497 | 4524 | ||
| 4525 | if ($(this).is('#model_vertexai_select')) { | ||
| 4526 | console.log('Vertex AI model changed to', value); | ||
| 4527 | oai_settings.vertexai_model = value; | ||
| 4528 | } | ||
| 4529 | |||
| 4498 | if ($(this).is('#model_mistralai_select')) { | 4530 | if ($(this).is('#model_mistralai_select')) { |
| 4499 | // Upgrade old mistral models to new naming scheme | 4531 | // Upgrade old mistral models to new naming scheme |
| 4500 | // would have done this in loadOpenAISettings, but it wasn't updating on preset change? | 4532 | // would have done this in loadOpenAISettings, but it wasn't updating on preset change? |
| @@ -4575,7 +4607,7 @@ async function onModelChange() { | |||
| 4575 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); | 4607 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 4576 | } | 4608 | } |
| 4577 | 4609 | ||
| 4578 | if (oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) { | 4610 | if ([chat_completion_sources.MAKERSUITE, chat_completion_sources.VERTEXAI].includes(oai_settings.chat_completion_source)) { |
| 4579 | if (oai_settings.max_context_unlocked) { | 4611 | if (oai_settings.max_context_unlocked) { |
| 4580 | $('#openai_max_context').attr('max', max_2mil); | 4612 | $('#openai_max_context').attr('max', max_2mil); |
| 4581 | } else if (value.includes('gemini-1.5-pro')) { | 4613 | } else if (value.includes('gemini-1.5-pro')) { |
| @@ -4943,6 +4975,19 @@ async function onConnectButtonClick(e) { | |||
| 4943 | } | 4975 | } |
| 4944 | } | 4976 | } |
| 4945 | 4977 | ||
| 4978 | if (oai_settings.chat_completion_source == chat_completion_sources.VERTEXAI) { | ||
| 4979 | const api_key_vertexai = String($('#api_key_vertexai').val()).trim(); | ||
| 4980 | |||
| 4981 | if (api_key_vertexai.length) { | ||
| 4982 | await writeSecret(SECRET_KEYS.VERTEXAI, api_key_vertexai); | ||
| 4983 | } | ||
| 4984 | |||
| 4985 | if (!secret_state[SECRET_KEYS.VERTEXAI] && !oai_settings.reverse_proxy) { | ||
| 4986 | console.log('No secret key saved for Vertex AI'); | ||
| 4987 | return; | ||
| 4988 | } | ||
| 4989 | } | ||
| 4990 | |||
| 4946 | if (oai_settings.chat_completion_source == chat_completion_sources.CLAUDE) { | 4991 | if (oai_settings.chat_completion_source == chat_completion_sources.CLAUDE) { |
| 4947 | const api_key_claude = String($('#api_key_claude').val()).trim(); | 4992 | const api_key_claude = String($('#api_key_claude').val()).trim(); |
| 4948 | 4993 | ||
| @@ -5120,6 +5165,9 @@ function toggleChatCompletionForms() { | |||
| 5120 | else if (oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) { | 5165 | else if (oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) { |
| 5121 | $('#model_google_select').trigger('change'); | 5166 | $('#model_google_select').trigger('change'); |
| 5122 | } | 5167 | } |
| 5168 | else if (oai_settings.chat_completion_source == chat_completion_sources.VERTEXAI) { | ||
| 5169 | $('#model_vertexai_select').trigger('change'); | ||
| 5170 | } | ||
| 5123 | else if (oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER) { | 5171 | else if (oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER) { |
| 5124 | $('#model_openrouter_select').trigger('change'); | 5172 | $('#model_openrouter_select').trigger('change'); |
| 5125 | } | 5173 | } |
| @@ -5281,6 +5329,8 @@ export function isImageInliningSupported() { | |||
| 5281 | ); | 5329 | ); |
| 5282 | case chat_completion_sources.MAKERSUITE: | 5330 | case chat_completion_sources.MAKERSUITE: |
| 5283 | return visionSupportedModels.some(model => oai_settings.google_model.includes(model)); | 5331 | return visionSupportedModels.some(model => oai_settings.google_model.includes(model)); |
| 5332 | case chat_completion_sources.VERTEXAI: | ||
| 5333 | return visionSupportedModels.some(model => oai_settings.vertexai_model.includes(model)); | ||
| 5284 | case chat_completion_sources.CLAUDE: | 5334 | case chat_completion_sources.CLAUDE: |
| 5285 | return visionSupportedModels.some(model => oai_settings.claude_model.includes(model)); | 5335 | return visionSupportedModels.some(model => oai_settings.claude_model.includes(model)); |
| 5286 | case chat_completion_sources.OPENROUTER: | 5336 | case chat_completion_sources.OPENROUTER: |
| @@ -5887,6 +5937,7 @@ export function initOpenAI() { | |||
| 5887 | $('#model_windowai_select').on('change', onModelChange); | 5937 | $('#model_windowai_select').on('change', onModelChange); |
| 5888 | $('#model_scale_select').on('change', onModelChange); | 5938 | $('#model_scale_select').on('change', onModelChange); |
| 5889 | $('#model_google_select').on('change', onModelChange); | 5939 | $('#model_google_select').on('change', onModelChange); |
| 5940 | $('#model_vertexai_select').on('change', onModelChange); | ||
| 5890 | $('#model_openrouter_select').on('change', onModelChange); | 5941 | $('#model_openrouter_select').on('change', onModelChange); |
| 5891 | $('#openrouter_group_models').on('change', onOpenrouterModelSortChange); | 5942 | $('#openrouter_group_models').on('change', onOpenrouterModelSortChange); |
| 5892 | $('#openrouter_sort_models').on('change', onOpenrouterModelSortChange); | 5943 | $('#openrouter_sort_models').on('change', onOpenrouterModelSortChange); |
| @@ -114,6 +114,7 @@ export function extractReasoningFromData(data, { | |||
| 114 | case chat_completion_sources.OPENROUTER: | 114 | case chat_completion_sources.OPENROUTER: |
| 115 | return data?.choices?.[0]?.message?.reasoning ?? ''; | 115 | return data?.choices?.[0]?.message?.reasoning ?? ''; |
| 116 | case chat_completion_sources.MAKERSUITE: | 116 | case chat_completion_sources.MAKERSUITE: |
| 117 | case chat_completion_sources.VERTEXAI: | ||
| 117 | return data?.responseContent?.parts?.filter(part => part.thought)?.map(part => part.text)?.join('\n\n') ?? ''; | 118 | return data?.responseContent?.parts?.filter(part => part.thought)?.map(part => part.text)?.join('\n\n') ?? ''; |
| 118 | case chat_completion_sources.CLAUDE: | 119 | case chat_completion_sources.CLAUDE: |
| 119 | return data?.content?.find(part => part.type === 'thinking')?.thinking ?? ''; | 120 | return data?.content?.find(part => part.type === 'thinking')?.thinking ?? ''; |
| @@ -16,6 +16,7 @@ export const SECRET_KEYS = { | |||
| 16 | AI21: 'api_key_ai21', | 16 | AI21: 'api_key_ai21', |
| 17 | SCALE_COOKIE: 'scale_cookie', | 17 | SCALE_COOKIE: 'scale_cookie', |
| 18 | MAKERSUITE: 'api_key_makersuite', | 18 | MAKERSUITE: 'api_key_makersuite', |
| 19 | VERTEXAI: 'api_key_vertexai', | ||
| 19 | SERPAPI: 'api_key_serpapi', | 20 | SERPAPI: 'api_key_serpapi', |
| 20 | MISTRALAI: 'api_key_mistralai', | 21 | MISTRALAI: 'api_key_mistralai', |
| 21 | TOGETHERAI: 'api_key_togetherai', | 22 | TOGETHERAI: 'api_key_togetherai', |
| @@ -56,6 +57,7 @@ const INPUT_MAP = { | |||
| 56 | [SECRET_KEYS.AI21]: '#api_key_ai21', | 57 | [SECRET_KEYS.AI21]: '#api_key_ai21', |
| 57 | [SECRET_KEYS.SCALE_COOKIE]: '#scale_cookie', | 58 | [SECRET_KEYS.SCALE_COOKIE]: '#scale_cookie', |
| 58 | [SECRET_KEYS.MAKERSUITE]: '#api_key_makersuite', | 59 | [SECRET_KEYS.MAKERSUITE]: '#api_key_makersuite', |
| 60 | [SECRET_KEYS.VERTEXAI]: '#api_key_vertexai', | ||
| 59 | [SECRET_KEYS.VLLM]: '#api_key_vllm', | 61 | [SECRET_KEYS.VLLM]: '#api_key_vllm', |
| 60 | [SECRET_KEYS.APHRODITE]: '#api_key_aphrodite', | 62 | [SECRET_KEYS.APHRODITE]: '#api_key_aphrodite', |
| 61 | [SECRET_KEYS.TABBY]: '#api_key_tabby', | 63 | [SECRET_KEYS.TABBY]: '#api_key_tabby', |
| @@ -4127,6 +4127,7 @@ function getModelOptions(quiet) { | |||
| 4127 | { id: 'model_openrouter_select', api: 'openai', type: chat_completion_sources.OPENROUTER }, | 4127 | { id: 'model_openrouter_select', api: 'openai', type: chat_completion_sources.OPENROUTER }, |
| 4128 | { id: 'model_ai21_select', api: 'openai', type: chat_completion_sources.AI21 }, | 4128 | { id: 'model_ai21_select', api: 'openai', type: chat_completion_sources.AI21 }, |
| 4129 | { id: 'model_google_select', api: 'openai', type: chat_completion_sources.MAKERSUITE }, | 4129 | { id: 'model_google_select', api: 'openai', type: chat_completion_sources.MAKERSUITE }, |
| 4130 | { id: 'model_vertexai_select', api: 'openai', type: chat_completion_sources.VERTEXAI }, | ||
| 4130 | { id: 'model_mistralai_select', api: 'openai', type: chat_completion_sources.MISTRALAI }, | 4131 | { id: 'model_mistralai_select', api: 'openai', type: chat_completion_sources.MISTRALAI }, |
| 4131 | { id: 'custom_model_id', api: 'openai', type: chat_completion_sources.CUSTOM }, | 4132 | { id: 'custom_model_id', api: 'openai', type: chat_completion_sources.CUSTOM }, |
| 4132 | { id: 'model_cohere_select', api: 'openai', type: chat_completion_sources.COHERE }, | 4133 | { id: 'model_cohere_select', api: 'openai', type: chat_completion_sources.COHERE }, |
| @@ -676,6 +676,10 @@ export function getTokenizerModel() { | |||
| 676 | return gemmaTokenizer; | 676 | return gemmaTokenizer; |
| 677 | } | 677 | } |
| 678 | 678 | ||
| 679 | if (oai_settings.chat_completion_source == chat_completion_sources.VERTEXAI) { | ||
| 680 | return gemmaTokenizer; | ||
| 681 | } | ||
| 682 | |||
| 679 | if (oai_settings.chat_completion_source == chat_completion_sources.AI21) { | 683 | if (oai_settings.chat_completion_source == chat_completion_sources.AI21) { |
| 680 | return jambaTokenizer; | 684 | return jambaTokenizer; |
| 681 | } | 685 | } |
| @@ -592,6 +592,7 @@ export class ToolManager { | |||
| 592 | chat_completion_sources.COHERE, | 592 | chat_completion_sources.COHERE, |
| 593 | chat_completion_sources.DEEPSEEK, | 593 | chat_completion_sources.DEEPSEEK, |
| 594 | chat_completion_sources.MAKERSUITE, | 594 | chat_completion_sources.MAKERSUITE, |
| 595 | chat_completion_sources.VERTEXAI, | ||
| 595 | chat_completion_sources.AI21, | 596 | chat_completion_sources.AI21, |
| 596 | chat_completion_sources.XAI, | 597 | chat_completion_sources.XAI, |
| 597 | chat_completion_sources.POLLINATIONS, | 598 | chat_completion_sources.POLLINATIONS, |
| @@ -168,6 +168,7 @@ export const CHAT_COMPLETION_SOURCES = { | |||
| 168 | OPENROUTER: 'openrouter', | 168 | OPENROUTER: 'openrouter', |
| 169 | AI21: 'ai21', | 169 | AI21: 'ai21', |
| 170 | MAKERSUITE: 'makersuite', | 170 | MAKERSUITE: 'makersuite', |
| 171 | VERTEXAI: 'vertexai', | ||
| 171 | MISTRALAI: 'mistralai', | 172 | MISTRALAI: 'mistralai', |
| 172 | CUSTOM: 'custom', | 173 | CUSTOM: 'custom', |
| 173 | COHERE: 'cohere', | 174 | COHERE: 'cohere', |
| @@ -52,6 +52,7 @@ const API_COHERE_V2 = 'https://api.cohere.ai/v2'; | |||
| 52 | const API_PERPLEXITY = 'https://api.perplexity.ai'; | 52 | const API_PERPLEXITY = 'https://api.perplexity.ai'; |
| 53 | const API_GROQ = 'https://api.groq.com/openai/v1'; | 53 | const API_GROQ = 'https://api.groq.com/openai/v1'; |
| 54 | const API_MAKERSUITE = 'https://generativelanguage.googleapis.com'; | 54 | const API_MAKERSUITE = 'https://generativelanguage.googleapis.com'; |
| 55 | const API_VERTEX_AI = 'https://us-central1-aiplatform.googleapis.com'; | ||
| 55 | const API_01AI = 'https://api.lingyiwanwu.com/v1'; | 56 | const API_01AI = 'https://api.lingyiwanwu.com/v1'; |
| 56 | const API_AI21 = 'https://api.ai21.com/studio/v1'; | 57 | const API_AI21 = 'https://api.ai21.com/studio/v1'; |
| 57 | const API_NANOGPT = 'https://nano-gpt.com/api/v1'; | 58 | const API_NANOGPT = 'https://nano-gpt.com/api/v1'; |
| @@ -337,12 +338,27 @@ async function sendScaleRequest(request, response) { | |||
| 337 | * @param {express.Response} response Express response | 338 | * @param {express.Response} response Express response |
| 338 | */ | 339 | */ |
| 339 | async function sendMakerSuiteRequest(request, response) { | 340 | async function sendMakerSuiteRequest(request, response) { |
| 340 | const apiUrl = new URL(request.body.reverse_proxy || API_MAKERSUITE); | 341 | const useVertexAi = request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.VERTEXAI; |
| 341 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE); | 342 | const apiName = useVertexAi ? 'Google Vertex AI' : 'Google AI Studio'; |
| 343 | let apiUrl; | ||
| 344 | let apiKey; | ||
| 342 | 345 | ||
| 343 | if (!request.body.reverse_proxy && !apiKey) { | 346 | if (useVertexAi) { |
| 344 | console.warn('Google AI Studio API key is missing.'); | 347 | apiUrl = new URL(request.body.reverse_proxy || API_VERTEX_AI); |
| 345 | return response.status(400).send({ error: true }); | 348 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.VERTEXAI); |
| 349 | |||
| 350 | if (!request.body.reverse_proxy && !apiKey) { | ||
| 351 | console.warn(`${apiName} API key is missing.`); | ||
| 352 | return response.status(400).send({ error: true }); | ||
| 353 | } | ||
| 354 | } else { | ||
| 355 | apiUrl = new URL(request.body.reverse_proxy || API_MAKERSUITE); | ||
| 356 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE); | ||
| 357 | |||
| 358 | if (!request.body.reverse_proxy && !apiKey) { | ||
| 359 | console.warn(`${apiName} API key is missing.`); | ||
| 360 | return response.status(400).send({ error: true }); | ||
| 361 | } | ||
| 346 | } | 362 | } |
| 347 | 363 | ||
| 348 | const model = String(request.body.model); | 364 | const model = String(request.body.model); |
| @@ -465,7 +481,7 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 465 | } | 481 | } |
| 466 | 482 | ||
| 467 | const body = getGeminiBody(); | 483 | const body = getGeminiBody(); |
| 468 | console.debug('Google AI Studio request:', body); | 484 | console.debug(`${apiName} request:`, body); |
| 469 | 485 | ||
| 470 | try { | 486 | try { |
| 471 | const controller = new AbortController(); | 487 | const controller = new AbortController(); |
| @@ -477,7 +493,13 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 477 | const apiVersion = getConfigValue('gemini.apiVersion', 'v1beta'); | 493 | const apiVersion = getConfigValue('gemini.apiVersion', 'v1beta'); |
| 478 | const responseType = (stream ? 'streamGenerateContent' : 'generateContent'); | 494 | const responseType = (stream ? 'streamGenerateContent' : 'generateContent'); |
| 479 | 495 | ||
| 480 | const generateResponse = await fetch(`${apiUrl.toString().replace(/\/$/, '')}/${apiVersion}/models/${model}:${responseType}?key=${apiKey}${stream ? '&alt=sse' : ''}`, { | 496 | let url; |
| 497 | if (useVertexAi) { | ||
| 498 | url = `${apiUrl.toString().replace(/\/$/, '')}/v1/publishers/google/models/${model}:${responseType}?key=${apiKey}${stream ? '&alt=sse' : ''}`; | ||
| 499 | } else { | ||
| 500 | url = `${apiUrl.toString().replace(/\/$/, '')}/${apiVersion}/models/${model}:${responseType}?key=${apiKey}${stream ? '&alt=sse' : ''}`; | ||
| 501 | } | ||
| 502 | const generateResponse = await fetch(url, { | ||
| 481 | body: JSON.stringify(body), | 503 | body: JSON.stringify(body), |
| 482 | method: 'POST', | 504 | method: 'POST', |
| 483 | headers: { | 505 | headers: { |
| @@ -498,7 +520,7 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 498 | } | 520 | } |
| 499 | } else { | 521 | } else { |
| 500 | if (!generateResponse.ok) { | 522 | if (!generateResponse.ok) { |
| 501 | console.warn(`Google AI Studio API returned error: ${generateResponse.status} ${generateResponse.statusText} ${await generateResponse.text()}`); | 523 | console.warn(`${apiName} API returned error: ${generateResponse.status} ${generateResponse.statusText} ${await generateResponse.text()}`); |
| 502 | return response.status(500).send({ error: true }); | 524 | return response.status(500).send({ error: true }); |
| 503 | } | 525 | } |
| 504 | 526 | ||
| @@ -507,7 +529,7 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 507 | 529 | ||
| 508 | const candidates = generateResponseJson?.candidates; | 530 | const candidates = generateResponseJson?.candidates; |
| 509 | if (!candidates || candidates.length === 0) { | 531 | if (!candidates || candidates.length === 0) { |
| 510 | let message = 'Google AI Studio API returned no candidate'; | 532 | let message = `${apiName} API returned no candidate`; |
| 511 | console.warn(message, generateResponseJson); | 533 | console.warn(message, generateResponseJson); |
| 512 | if (generateResponseJson?.promptFeedback?.blockReason) { | 534 | if (generateResponseJson?.promptFeedback?.blockReason) { |
| 513 | message += `\nPrompt was blocked due to : ${generateResponseJson.promptFeedback.blockReason}`; | 535 | message += `\nPrompt was blocked due to : ${generateResponseJson.promptFeedback.blockReason}`; |
| @@ -518,11 +540,11 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 518 | const responseContent = candidates[0].content ?? candidates[0].output; | 540 | const responseContent = candidates[0].content ?? candidates[0].output; |
| 519 | const functionCall = (candidates?.[0]?.content?.parts ?? []).some(part => part.functionCall); | 541 | const functionCall = (candidates?.[0]?.content?.parts ?? []).some(part => part.functionCall); |
| 520 | const inlineData = (candidates?.[0]?.content?.parts ?? []).some(part => part.inlineData); | 542 | const inlineData = (candidates?.[0]?.content?.parts ?? []).some(part => part.inlineData); |
| 521 | console.debug('Google AI Studio response:', util.inspect(generateResponseJson, { depth: 5, colors: true })); | 543 | console.debug(`${apiName} response:`, util.inspect(generateResponseJson, { depth: 5, colors: true })); |
| 522 | 544 | ||
| 523 | const responseText = typeof responseContent === 'string' ? responseContent : responseContent?.parts?.filter(part => !part.thought)?.map(part => part.text)?.join('\n\n'); | 545 | const responseText = typeof responseContent === 'string' ? responseContent : responseContent?.parts?.filter(part => !part.thought)?.map(part => part.text)?.join('\n\n'); |
| 524 | if (!responseText && !functionCall && !inlineData) { | 546 | if (!responseText && !functionCall && !inlineData) { |
| 525 | let message = 'Google AI Studio Candidate text empty'; | 547 | let message = `${apiName} Candidate text empty`; |
| 526 | console.warn(message, generateResponseJson); | 548 | console.warn(message, generateResponseJson); |
| 527 | return response.send({ error: { message } }); | 549 | return response.send({ error: { message } }); |
| 528 | } | 550 | } |
| @@ -532,7 +554,7 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 532 | return response.send(reply); | 554 | return response.send(reply); |
| 533 | } | 555 | } |
| 534 | } catch (error) { | 556 | } catch (error) { |
| 535 | console.error('Error communicating with Google AI Studio API: ', error); | 557 | console.error(`Error communicating with ${apiName} API:`, error); |
| 536 | if (!response.headersSent) { | 558 | if (!response.headersSent) { |
| 537 | return response.status(500).send({ error: true }); | 559 | return response.status(500).send({ error: true }); |
| 538 | } | 560 | } |
| @@ -1189,6 +1211,7 @@ router.post('/generate', function (request, response) { | |||
| 1189 | case CHAT_COMPLETION_SOURCES.SCALE: return sendScaleRequest(request, response); | 1211 | case CHAT_COMPLETION_SOURCES.SCALE: return sendScaleRequest(request, response); |
| 1190 | case CHAT_COMPLETION_SOURCES.AI21: return sendAI21Request(request, response); | 1212 | case CHAT_COMPLETION_SOURCES.AI21: return sendAI21Request(request, response); |
| 1191 | case CHAT_COMPLETION_SOURCES.MAKERSUITE: return sendMakerSuiteRequest(request, response); | 1213 | case CHAT_COMPLETION_SOURCES.MAKERSUITE: return sendMakerSuiteRequest(request, response); |
| 1214 | case CHAT_COMPLETION_SOURCES.VERTEXAI: return sendMakerSuiteRequest(request, response); | ||
| 1192 | case CHAT_COMPLETION_SOURCES.MISTRALAI: return sendMistralAIRequest(request, response); | 1215 | case CHAT_COMPLETION_SOURCES.MISTRALAI: return sendMistralAIRequest(request, response); |
| 1193 | case CHAT_COMPLETION_SOURCES.COHERE: return sendCohereRequest(request, response); | 1216 | case CHAT_COMPLETION_SOURCES.COHERE: return sendCohereRequest(request, response); |
| 1194 | case CHAT_COMPLETION_SOURCES.DEEPSEEK: return sendDeepSeekRequest(request, response); | 1217 | case CHAT_COMPLETION_SOURCES.DEEPSEEK: return sendDeepSeekRequest(request, response); |
| @@ -7,6 +7,7 @@ import { readSecret, SECRET_KEYS } from './secrets.js'; | |||
| 7 | import { GEMINI_SAFETY } from '../constants.js'; | 7 | import { GEMINI_SAFETY } from '../constants.js'; |
| 8 | 8 | ||
| 9 | const API_MAKERSUITE = 'https://generativelanguage.googleapis.com'; | 9 | const API_MAKERSUITE = 'https://generativelanguage.googleapis.com'; |
| 10 | const API_VERTEX_AI = 'https://us-central1-aiplatform.googleapis.com'; | ||
| 10 | 11 | ||
| 11 | export const router = express.Router(); | 12 | export const router = express.Router(); |
| 12 | 13 | ||
| @@ -14,12 +15,27 @@ router.post('/caption-image', async (request, response) => { | |||
| 14 | try { | 15 | try { |
| 15 | const mimeType = request.body.image.split(';')[0].split(':')[1]; | 16 | const mimeType = request.body.image.split(';')[0].split(':')[1]; |
| 16 | const base64Data = request.body.image.split(',')[1]; | 17 | const base64Data = request.body.image.split(',')[1]; |
| 17 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE); | 18 | const useVertexAi = request.body.api === 'vertexai'; |
| 18 | const apiUrl = new URL(request.body.reverse_proxy || API_MAKERSUITE); | 19 | const apiName = useVertexAi ? 'Google Vertex AI' : 'Google AI Studio'; |
| 20 | let apiKey; | ||
| 21 | let apiUrl; | ||
| 22 | if (useVertexAi) { | ||
| 23 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.VERTEXAI); | ||
| 24 | apiUrl = new URL(request.body.reverse_proxy || API_VERTEX_AI); | ||
| 25 | } else { | ||
| 26 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE); | ||
| 27 | apiUrl = new URL(request.body.reverse_proxy || API_MAKERSUITE); | ||
| 28 | } | ||
| 19 | const model = request.body.model || 'gemini-2.0-flash'; | 29 | const model = request.body.model || 'gemini-2.0-flash'; |
| 20 | const url = `${apiUrl.origin}/v1beta/models/${model}:generateContent?key=${apiKey}`; | 30 | let url; |
| 31 | if (useVertexAi) { | ||
| 32 | url = `${apiUrl.origin}/v1/publishers/google/models/${model}:generateContent?key=${apiKey}`; | ||
| 33 | } else { | ||
| 34 | url = `${apiUrl.origin}/v1beta/models/${model}:generateContent?key=${apiKey}`; | ||
| 35 | } | ||
| 21 | const body = { | 36 | const body = { |
| 22 | contents: [{ | 37 | contents: [{ |
| 38 | role: 'user', | ||
| 23 | parts: [ | 39 | parts: [ |
| 24 | { text: request.body.prompt }, | 40 | { text: request.body.prompt }, |
| 25 | { | 41 | { |
| @@ -32,7 +48,7 @@ router.post('/caption-image', async (request, response) => { | |||
| 32 | safetySettings: GEMINI_SAFETY, | 48 | safetySettings: GEMINI_SAFETY, |
| 33 | }; | 49 | }; |
| 34 | 50 | ||
| 35 | console.debug('Multimodal captioning request', model, body); | 51 | console.debug(`${apiName} captioning request`, model, body); |
| 36 | 52 | ||
| 37 | const result = await fetch(url, { | 53 | const result = await fetch(url, { |
| 38 | body: JSON.stringify(body), | 54 | body: JSON.stringify(body), |
| @@ -44,13 +60,13 @@ router.post('/caption-image', async (request, response) => { | |||
| 44 | 60 | ||
| 45 | if (!result.ok) { | 61 | if (!result.ok) { |
| 46 | const error = await result.json(); | 62 | const error = await result.json(); |
| 47 | console.error(`Google AI Studio API returned error: ${result.status} ${result.statusText}`, error); | 63 | console.error(`${apiName} API returned error: ${result.status} ${result.statusText}`, error); |
| 48 | return response.status(500).send({ error: true }); | 64 | return response.status(500).send({ error: true }); |
| 49 | } | 65 | } |
| 50 | 66 | ||
| 51 | /** @type {any} */ | 67 | /** @type {any} */ |
| 52 | const data = await result.json(); | 68 | const data = await result.json(); |
| 53 | console.info('Multimodal captioning response', data); | 69 | console.info(`${apiName} captioning response`, data); |
| 54 | 70 | ||
| 55 | const candidates = data?.candidates; | 71 | const candidates = data?.candidates; |
| 56 | if (!candidates) { | 72 | if (!candidates) { |
| @@ -26,6 +26,7 @@ export const SECRET_KEYS = { | |||
| 26 | ONERING_URL: 'oneringtranslator_url', | 26 | ONERING_URL: 'oneringtranslator_url', |
| 27 | DEEPLX_URL: 'deeplx_url', | 27 | DEEPLX_URL: 'deeplx_url', |
| 28 | MAKERSUITE: 'api_key_makersuite', | 28 | MAKERSUITE: 'api_key_makersuite', |
| 29 | VERTEXAI: 'api_key_vertexai', | ||
| 29 | SERPAPI: 'api_key_serpapi', | 30 | SERPAPI: 'api_key_serpapi', |
| 30 | TOGETHERAI: 'api_key_togetherai', | 31 | TOGETHERAI: 'api_key_togetherai', |
| 31 | MISTRALAI: 'api_key_mistralai', | 32 | MISTRALAI: 'api_key_mistralai', |
| @@ -463,7 +463,7 @@ export function getTokenizerModel(requestModel) { | |||
| 463 | return 'deepseek'; | 463 | return 'deepseek'; |
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | if (requestModel.includes('gemma') || requestModel.includes('gemini')) { | 466 | if (requestModel.includes('gemma') || requestModel.includes('gemini') || requestModel.includes('learnlm')) { |
| 467 | return 'gemma'; | 467 | return 'gemma'; |
| 468 | } | 468 | } |
| 469 | 469 | ||