Add region option for vertex express mode to access more models (#4155) * add region option for vertex express mode to access more models * add region option for vertex express mode to access more models * fix: Consolidate duplicate 'vertexai_region' input * feat: add vertex region suggestion datalist & update caption endpoint to correctly handle region * Adjust global projectless Vertex endpoint * Remove pointless slash trim * Skill issue --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -3257,19 +3257,38 @@ | |||
| 3257 | <!-- Express Mode Configuration --> | 3257 | <!-- Express Mode Configuration --> |
| 3258 | <div id="vertexai_express_config" class="vertexai-auth-section" data-mode="express"> | 3258 | <div id="vertexai_express_config" class="vertexai-auth-section" data-mode="express"> |
| 3259 | <h4> | 3259 | <h4> |
| 3260 | <span data-i18n="Google Vertex AI API Key"> | 3260 | <span data-i18n="Google Vertex AI Configuration"> |
| 3261 | Google Vertex AI API Key | 3261 | Google Vertex AI Configuration |
| 3262 | </span> | 3262 | </span> |
| 3263 | <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/start/express-mode/overview" data-i18n="(Express mode)" target="_blank" rel="noopener noreferrer"> | 3263 | <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/start/express-mode/overview" data-i18n="(Express mode)" target="_blank" rel="noopener noreferrer"> |
| 3264 | (Express mode) | 3264 | (Express mode) |
| 3265 | </a> | 3265 | </a> |
| 3266 | </h4> | 3266 | </h4> |
| 3267 | <div class="flex-container"> | 3267 | <!-- API Key --> |
| 3268 | <input id="api_key_vertexai" name="api_key_vertexai" class="text_pole flex1" value="" type="text" autocomplete="off"> | 3268 | <div class="flex-container flexFlowColumn"> |
| 3269 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_vertexai"></div> | 3269 | <label for="api_key_vertexai" data-i18n="API Key">API Key:</label> |
| 3270 | <div class="flex-container"> | ||
| 3271 | <input id="api_key_vertexai" name="api_key_vertexai" class="text_pole flex1" value="" type="text" autocomplete="off"> | ||
| 3272 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_vertexai"></div> | ||
| 3273 | </div> | ||
| 3274 | <div data-for="api_key_vertexai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> | ||
| 3275 | For privacy reasons, your API key will be hidden after you click 'Connect'. | ||
| 3276 | </div> | ||
| 3270 | </div> | 3277 | </div> |
| 3271 | <div data-for="api_key_vertexai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> | 3278 | <!-- Project ID --> |
| 3272 | For privacy reasons, your API key will be hidden after you click 'Connect'. | 3279 | <div class="flex-container flexFlowColumn marginTop10"> |
| 3280 | <label for="vertexai_express_project_id"> | ||
| 3281 | <span data-i18n="Project ID">Project ID:</span> | ||
| 3282 | </label> | ||
| 3283 | <div class="flex-container"> | ||
| 3284 | <input id="vertexai_express_project_id" name="vertexai_express_project_id" class="text_pole flex1" value="" type="text" autocomplete="off" placeholder="Enter your Project ID"> | ||
| 3285 | </div> | ||
| 3286 | <div class="toggle-description justifyLeft marginBot5"> | ||
| 3287 | <small data-i18n="Project ID is required when selecting regions other than the default (us-central1). You can find this in a model 404 error message."> | ||
| 3288 | `Project ID` is only required when selecting regions other than the default (us-central1).<br> | ||
| 3289 | You can find this in a model 404 error message. | ||
| 3290 | </small> | ||
| 3291 | </div> | ||
| 3273 | </div> | 3292 | </div> |
| 3274 | </div> | 3293 | </div> |
| 3275 | 3294 | ||
| @@ -3283,20 +3302,6 @@ | |||
| 3283 | <i class="fa-solid fa-circle-question"></i> | 3302 | <i class="fa-solid fa-circle-question"></i> |
| 3284 | </a> | 3303 | </a> |
| 3285 | </h4> | 3304 | </h4> |
| 3286 | |||
| 3287 | <!-- Region --> | ||
| 3288 | <div class="flex-container flexFlowColumn"> | ||
| 3289 | <label for="vertexai_region"> | ||
| 3290 | <span data-i18n="Region"> | ||
| 3291 | Region: | ||
| 3292 | </span> | ||
| 3293 | <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations" target="_blank" rel="noopener noreferrer" title="View available regions and models" data-i18n="[title]View available regions and models" class="notes-link"> | ||
| 3294 | <span class="fa-solid fa-circle-question note-link-span"></span> | ||
| 3295 | </a> | ||
| 3296 | </label> | ||
| 3297 | <input id="vertexai_region" name="vertexai_region" class="text_pole flex1" value="us-central1" type="text" autocomplete="off" placeholder="e.g., global, us-central1, europe-west1, asia-northeast1"> | ||
| 3298 | </div> | ||
| 3299 | |||
| 3300 | <!-- Service Account JSON Content --> | 3305 | <!-- Service Account JSON Content --> |
| 3301 | <div class="flex-container flexFlowColumn"> | 3306 | <div class="flex-container flexFlowColumn"> |
| 3302 | <label for="vertexai_service_account_json" data-i18n="Service Account JSON Content">Service Account JSON Content:</label> | 3307 | <label for="vertexai_service_account_json" data-i18n="Service Account JSON Content">Service Account JSON Content:</label> |
| @@ -3316,12 +3321,48 @@ | |||
| 3316 | </div> | 3321 | </div> |
| 3317 | </div> | 3322 | </div> |
| 3318 | 3323 | ||
| 3324 | <!-- Region --> | ||
| 3325 | <div class="flex-container flexFlowColumn"> | ||
| 3326 | <label for="vertexai_region"> | ||
| 3327 | <span data-i18n="Region"> | ||
| 3328 | Region: | ||
| 3329 | </span> | ||
| 3330 | <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations" target="_blank" rel="noopener noreferrer" title="View available regions and models" data-i18n="[title]View available regions and models" class="notes-link"> | ||
| 3331 | <span class="fa-solid fa-circle-question note-link-span"></span> | ||
| 3332 | </a> | ||
| 3333 | </label> | ||
| 3334 | <input id="vertexai_region" name="vertexai_region" class="text_pole flex1" value="us-central1" type="text" autocomplete="off" placeholder="e.g., global, us-central1, europe-west1, asia-northeast1" list="vertexai_region_suggestions"> | ||
| 3335 | |||
| 3336 | <datalist id="vertexai_region_suggestions"> | ||
| 3337 | <option value="global">global</option> | ||
| 3338 | <option value="us-central1">us-central1</option> | ||
| 3339 | <option value="us-east1">us-east1</option> | ||
| 3340 | <option value="us-east4">us-east4</option> | ||
| 3341 | <option value="us-west1">us-west1</option> | ||
| 3342 | <option value="us-west2">us-west2</option> | ||
| 3343 | <option value="us-west3">us-west3</option> | ||
| 3344 | <option value="us-west4">us-west4</option> | ||
| 3345 | <option value="europe-west1">europe-west1</option> | ||
| 3346 | <option value="europe-west2">europe-west2</option> | ||
| 3347 | <option value="europe-west3">europe-west3</option> | ||
| 3348 | <option value="europe-west4">europe-west4</option> | ||
| 3349 | <option value="europe-west6">europe-west6</option> | ||
| 3350 | <option value="europe-central2">europe-central2</option> | ||
| 3351 | <option value="asia-northeast1">asia-northeast1</option> | ||
| 3352 | <option value="asia-northeast3">asia-northeast3</option> | ||
| 3353 | <option value="asia-southeast1">asia-southeast1</option> | ||
| 3354 | <option value="asia-south1">asia-south1</option> | ||
| 3355 | <option value="australia-southeast1">australia-southeast1</option> | ||
| 3356 | </datalist> | ||
| 3357 | </div> | ||
| 3358 | |||
| 3319 | <!-- Model Selection --> | 3359 | <!-- Model Selection --> |
| 3320 | <div> | 3360 | <div> |
| 3321 | <h4 data-i18n="Google Model">Google Model</h4> | 3361 | <h4 data-i18n="Google Model">Google Model</h4> |
| 3322 | <select id="model_vertexai_select"> | 3362 | <select id="model_vertexai_select"> |
| 3323 | <!-- Express Mode Models --> | 3363 | <!-- Express Mode Models --> |
| 3324 | <optgroup id="vertexai_express_models" label="Express Mode Models" data-mode="express"> | 3364 | <optgroup id="vertexai_express_models" label="Express Mode Models" data-mode="express"> |
| 3365 | <option value="gemini-2.5-pro-preview-06-05">gemini-2.5-pro-preview-06-05 (global region, Project ID required)</option> | ||
| 3325 | <option value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> | 3366 | <option value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option> |
| 3326 | <option value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> | 3367 | <option value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> |
| 3327 | <option value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> | 3368 | <option value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option> |
| @@ -60,6 +60,7 @@ export async function getMultimodalCaption(base64Img, prompt) { | |||
| 60 | if (extension_settings.caption.multimodal_api === 'vertexai') { | 60 | if (extension_settings.caption.multimodal_api === 'vertexai') { |
| 61 | requestBody.vertexai_auth_mode = oai_settings.vertexai_auth_mode; | 61 | requestBody.vertexai_auth_mode = oai_settings.vertexai_auth_mode; |
| 62 | requestBody.vertexai_region = oai_settings.vertexai_region; | 62 | requestBody.vertexai_region = oai_settings.vertexai_region; |
| 63 | requestBody.vertexai_express_project_id = oai_settings.vertexai_express_project_id; | ||
| 63 | } | 64 | } |
| 64 | 65 | ||
| 65 | if (isOllama) { | 66 | if (isOllama) { |
| @@ -240,6 +240,7 @@ const sensitiveFields = [ | |||
| 240 | 'custom_exclude_body', | 240 | 'custom_exclude_body', |
| 241 | 'custom_include_headers', | 241 | 'custom_include_headers', |
| 242 | 'vertexai_region', | 242 | 'vertexai_region', |
| 243 | 'vertexai_express_project_id', | ||
| 243 | ]; | 244 | ]; |
| 244 | 245 | ||
| 245 | /** | 246 | /** |
| @@ -314,6 +315,7 @@ export const settingsToUpdate = { | |||
| 314 | use_makersuite_sysprompt: ['#use_makersuite_sysprompt', 'use_makersuite_sysprompt', true, false], | 315 | use_makersuite_sysprompt: ['#use_makersuite_sysprompt', 'use_makersuite_sysprompt', true, false], |
| 315 | vertexai_auth_mode: ['#vertexai_auth_mode', 'vertexai_auth_mode', false, true], | 316 | vertexai_auth_mode: ['#vertexai_auth_mode', 'vertexai_auth_mode', false, true], |
| 316 | vertexai_region: ['#vertexai_region', 'vertexai_region', false, true], | 317 | vertexai_region: ['#vertexai_region', 'vertexai_region', false, true], |
| 318 | vertexai_express_project_id: ['#vertexai_express_project_id', 'vertexai_express_project_id', false, true], | ||
| 317 | use_alt_scale: ['#use_alt_scale', 'use_alt_scale', true, true], | 319 | use_alt_scale: ['#use_alt_scale', 'use_alt_scale', true, true], |
| 318 | squash_system_messages: ['#squash_system_messages', 'squash_system_messages', true, false], | 320 | squash_system_messages: ['#squash_system_messages', 'squash_system_messages', true, false], |
| 319 | image_inlining: ['#openai_image_inlining', 'image_inlining', true, false], | 321 | image_inlining: ['#openai_image_inlining', 'image_inlining', true, false], |
| @@ -399,6 +401,7 @@ const default_settings = { | |||
| 399 | use_makersuite_sysprompt: true, | 401 | use_makersuite_sysprompt: true, |
| 400 | vertexai_auth_mode: 'express', | 402 | vertexai_auth_mode: 'express', |
| 401 | vertexai_region: 'us-central1', | 403 | vertexai_region: 'us-central1', |
| 404 | vertexai_express_project_id: '', | ||
| 402 | use_alt_scale: false, | 405 | use_alt_scale: false, |
| 403 | squash_system_messages: false, | 406 | squash_system_messages: false, |
| 404 | image_inlining: false, | 407 | image_inlining: false, |
| @@ -487,6 +490,7 @@ const oai_settings = { | |||
| 487 | use_makersuite_sysprompt: true, | 490 | use_makersuite_sysprompt: true, |
| 488 | vertexai_auth_mode: 'express', | 491 | vertexai_auth_mode: 'express', |
| 489 | vertexai_region: 'us-central1', | 492 | vertexai_region: 'us-central1', |
| 493 | vertexai_express_project_id: '', | ||
| 490 | use_alt_scale: false, | 494 | use_alt_scale: false, |
| 491 | squash_system_messages: false, | 495 | squash_system_messages: false, |
| 492 | image_inlining: false, | 496 | image_inlining: false, |
| @@ -2319,6 +2323,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2319 | if (isVertexAI) { | 2323 | if (isVertexAI) { |
| 2320 | generate_data['vertexai_auth_mode'] = oai_settings.vertexai_auth_mode; | 2324 | generate_data['vertexai_auth_mode'] = oai_settings.vertexai_auth_mode; |
| 2321 | generate_data['vertexai_region'] = oai_settings.vertexai_region; | 2325 | generate_data['vertexai_region'] = oai_settings.vertexai_region; |
| 2326 | generate_data['vertexai_express_project_id'] = oai_settings.vertexai_express_project_id; | ||
| 2322 | } | 2327 | } |
| 2323 | } | 2328 | } |
| 2324 | 2329 | ||
| @@ -3552,6 +3557,7 @@ function loadOpenAISettings(data, settings) { | |||
| 3552 | oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality; | 3557 | oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality; |
| 3553 | oai_settings.video_inlining = settings.video_inlining ?? default_settings.video_inlining; | 3558 | oai_settings.video_inlining = settings.video_inlining ?? default_settings.video_inlining; |
| 3554 | oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check; | 3559 | oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check; |
| 3560 | oai_settings.vertexai_express_project_id = settings.vertexai_express_project_id ?? default_settings.vertexai_express_project_id; | ||
| 3555 | oai_settings.show_thoughts = settings.show_thoughts ?? default_settings.show_thoughts; | 3561 | oai_settings.show_thoughts = settings.show_thoughts ?? default_settings.show_thoughts; |
| 3556 | oai_settings.reasoning_effort = settings.reasoning_effort ?? default_settings.reasoning_effort; | 3562 | oai_settings.reasoning_effort = settings.reasoning_effort ?? default_settings.reasoning_effort; |
| 3557 | oai_settings.enable_web_search = settings.enable_web_search ?? default_settings.enable_web_search; | 3563 | oai_settings.enable_web_search = settings.enable_web_search ?? default_settings.enable_web_search; |
| @@ -3589,6 +3595,7 @@ function loadOpenAISettings(data, settings) { | |||
| 3589 | if (settings.use_makersuite_sysprompt !== undefined) oai_settings.use_makersuite_sysprompt = !!settings.use_makersuite_sysprompt; | 3595 | if (settings.use_makersuite_sysprompt !== undefined) oai_settings.use_makersuite_sysprompt = !!settings.use_makersuite_sysprompt; |
| 3590 | if (settings.vertexai_auth_mode !== undefined) oai_settings.vertexai_auth_mode = settings.vertexai_auth_mode; | 3596 | if (settings.vertexai_auth_mode !== undefined) oai_settings.vertexai_auth_mode = settings.vertexai_auth_mode; |
| 3591 | if (settings.vertexai_region !== undefined) oai_settings.vertexai_region = settings.vertexai_region; | 3597 | if (settings.vertexai_region !== undefined) oai_settings.vertexai_region = settings.vertexai_region; |
| 3598 | if (settings.vertexai_express_project_id !== undefined) oai_settings.vertexai_express_project_id = settings.vertexai_express_project_id; | ||
| 3592 | if (settings.use_alt_scale !== undefined) { oai_settings.use_alt_scale = !!settings.use_alt_scale; updateScaleForm(); } | 3599 | if (settings.use_alt_scale !== undefined) { oai_settings.use_alt_scale = !!settings.use_alt_scale; updateScaleForm(); } |
| 3593 | $('#stream_toggle').prop('checked', oai_settings.stream_openai); | 3600 | $('#stream_toggle').prop('checked', oai_settings.stream_openai); |
| 3594 | $('#api_url_scale').val(oai_settings.api_url_scale); | 3601 | $('#api_url_scale').val(oai_settings.api_url_scale); |
| @@ -3650,6 +3657,7 @@ function loadOpenAISettings(data, settings) { | |||
| 3650 | $('#use_makersuite_sysprompt').prop('checked', oai_settings.use_makersuite_sysprompt); | 3657 | $('#use_makersuite_sysprompt').prop('checked', oai_settings.use_makersuite_sysprompt); |
| 3651 | $('#vertexai_auth_mode').val(oai_settings.vertexai_auth_mode); | 3658 | $('#vertexai_auth_mode').val(oai_settings.vertexai_auth_mode); |
| 3652 | $('#vertexai_region').val(oai_settings.vertexai_region); | 3659 | $('#vertexai_region').val(oai_settings.vertexai_region); |
| 3660 | $('#vertexai_express_project_id').val(oai_settings.vertexai_express_project_id); | ||
| 3653 | // Don't display Service Account JSON in textarea - it's stored in backend secrets | 3661 | // Don't display Service Account JSON in textarea - it's stored in backend secrets |
| 3654 | $('#vertexai_service_account_json').val(''); | 3662 | $('#vertexai_service_account_json').val(''); |
| 3655 | updateVertexAIServiceAccountStatus(); | 3663 | updateVertexAIServiceAccountStatus(); |
| @@ -3980,6 +3988,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { | |||
| 3980 | use_makersuite_sysprompt: settings.use_makersuite_sysprompt, | 3988 | use_makersuite_sysprompt: settings.use_makersuite_sysprompt, |
| 3981 | vertexai_auth_mode: settings.vertexai_auth_mode, | 3989 | vertexai_auth_mode: settings.vertexai_auth_mode, |
| 3982 | vertexai_region: settings.vertexai_region, | 3990 | vertexai_region: settings.vertexai_region, |
| 3991 | vertexai_express_project_id: settings.vertexai_express_project_id, | ||
| 3983 | use_alt_scale: settings.use_alt_scale, | 3992 | use_alt_scale: settings.use_alt_scale, |
| 3984 | squash_system_messages: settings.squash_system_messages, | 3993 | squash_system_messages: settings.squash_system_messages, |
| 3985 | image_inlining: settings.image_inlining, | 3994 | image_inlining: settings.image_inlining, |
| @@ -6378,6 +6387,10 @@ export function initOpenAI() { | |||
| 6378 | oai_settings.vertexai_region = String($(this).val()); | 6387 | oai_settings.vertexai_region = String($(this).val()); |
| 6379 | saveSettingsDebounced(); | 6388 | saveSettingsDebounced(); |
| 6380 | }); | 6389 | }); |
| 6390 | $('#vertexai_express_project_id').on('input', function () { | ||
| 6391 | oai_settings.vertexai_express_project_id = String($(this).val()); | ||
| 6392 | saveSettingsDebounced(); | ||
| 6393 | }); | ||
| 6381 | $('#vertexai_service_account_json').on('input', onVertexAIServiceAccountJsonChange); | 6394 | $('#vertexai_service_account_json').on('input', onVertexAIServiceAccountJsonChange); |
| 6382 | $('#vertexai_validate_service_account').on('click', onVertexAIValidateServiceAccount); | 6395 | $('#vertexai_validate_service_account').on('click', onVertexAIValidateServiceAccount); |
| 6383 | $('#vertexai_clear_service_account').on('click', onVertexAIClearServiceAccount); | 6396 | $('#vertexai_clear_service_account').on('click', onVertexAIClearServiceAccount); |
| @@ -493,7 +493,14 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 493 | if (authType === 'express') { | 493 | if (authType === 'express') { |
| 494 | // For Express mode (API key authentication), use the key parameter | 494 | // For Express mode (API key authentication), use the key parameter |
| 495 | const keyParam = authHeader.replace('Bearer ', ''); | 495 | const keyParam = authHeader.replace('Bearer ', ''); |
| 496 | url = `${apiUrl.toString().replace(/\/$/, '')}/v1/publishers/google/models/${model}:${responseType}?key=${keyParam}${stream ? '&alt=sse' : ''}`; | 496 | const region = request.body.vertexai_region || 'us-central1'; |
| 497 | const projectId = request.body.vertexai_express_project_id; | ||
| 498 | const baseUrl = region === 'global' | ||
| 499 | ? 'https://aiplatform.googleapis.com' | ||
| 500 | : `https://${region}-aiplatform.googleapis.com`; | ||
| 501 | url = projectId | ||
| 502 | ? `https://aiplatform.googleapis.com/v1/projects/${projectId}/locations/${region}/publishers/google/models/${model}:generateContent?key=${keyParam}${stream ? '&alt=sse' : ''}` | ||
| 503 | : `${baseUrl}/v1/publishers/google/models/${model}:generateContent?key=${keyParam}${stream ? '&alt=sse' : ''}`; | ||
| 497 | } else if (authType === 'full') { | 504 | } else if (authType === 'full') { |
| 498 | // For Full mode (service account authentication), use project-specific URL | 505 | // For Full mode (service account authentication), use project-specific URL |
| 499 | // Get project ID from Service Account JSON | 506 | // Get project ID from Service Account JSON |
| @@ -104,6 +104,7 @@ export async function getAccessToken(jwtToken) { | |||
| 104 | throw new Error(`Failed to get access token: ${error}`); | 104 | throw new Error(`Failed to get access token: ${error}`); |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | /** @type {any} */ | ||
| 107 | const data = await response.json(); | 108 | const data = await response.json(); |
| 108 | return data.access_token; | 109 | return data.access_token; |
| 109 | } | 110 | } |
| @@ -149,8 +150,14 @@ router.post('/caption-image', async (request, response) => { | |||
| 149 | if (authType === 'express') { | 150 | if (authType === 'express') { |
| 150 | // Express mode: use API key parameter | 151 | // Express mode: use API key parameter |
| 151 | const keyParam = authHeader.replace('Bearer ', ''); | 152 | const keyParam = authHeader.replace('Bearer ', ''); |
| 152 | const apiUrl = trimTrailingSlash(request.body.reverse_proxy || API_VERTEX_AI); | 153 | const region = request.body.vertexai_region || 'us-central1'; |
| 153 | url = `${apiUrl}/v1/publishers/google/models/${model}:generateContent?key=${keyParam}`; | 154 | const projectId = request.body.vertexai_express_project_id; |
| 155 | const baseUrl = region === 'global' | ||
| 156 | ? 'https://aiplatform.googleapis.com' | ||
| 157 | : `https://${region}-aiplatform.googleapis.com`; | ||
| 158 | url = projectId | ||
| 159 | ? `https://aiplatform.googleapis.com/v1/projects/${projectId}/locations/${region}/publishers/google/models/${model}:generateContent?key=${keyParam}` | ||
| 160 | : `${baseUrl}/v1/publishers/google/models/${model}:generateContent?key=${keyParam}`; | ||
| 154 | } else if (authType === 'full') { | 161 | } else if (authType === 'full') { |
| 155 | // Full mode: use project-specific URL with Authorization header | 162 | // Full mode: use project-specific URL with Authorization header |
| 156 | // Get project ID from Service Account JSON | 163 | // Get project ID from Service Account JSON |