Gemini: Add image request settings (#4838) * Gemini: Add image request settings * Allow aspect ratio for 2.5 flash
Signed| @@ -563,3 +563,7 @@ label[for="bind_preset_to_connection"]:has(input:checked) { | ||
| 563 | 563 | filter: grayscale(0.5); |
| 564 | 564 | cursor: not-allowed; |
| 565 | 565 | } |
| 566 | + | |
| 567 | +#request_images_block:has(#openai_request_images:not(:checked)) #request_images_settings { | |
| 568 | + display: none; | |
| 569 | +} | |
| @@ -2022,7 +2022,7 @@ | ||
| 2022 | 2022 | </div> |
| 2023 | 2023 | </div> |
| 2024 | 2024 | </div> |
| 2025 | 2025 | <div id="request_images_block" class="range-block" data-source="makersuite,vertexai"> |
| 2026 | 2026 | <label for="openai_request_images" class="checkbox_label widthFreeExpand"> |
| 2027 | 2027 | <input id="openai_request_images" type="checkbox" /> |
| 2028 | 2028 | <span> |
| @@ -2038,6 +2038,37 @@ | ||
| 2038 | 2038 | Incompatible with the following features: function calling, web search, system prompt. |
| 2039 | 2039 | </em> |
| 2040 | 2040 | </div> |
| 2041 | + <div id="request_images_settings" class="flex-container wide100p textAlignCenter"> | |
| 2042 | + <div class="flex1"> | |
| 2043 | + <label for="request_image_resolution"> | |
| 2044 | + <small data-i18n="Resolution">Resolution</small> | |
| 2045 | + </label> | |
| 2046 | + <select id="request_image_resolution" class="text_pole"> | |
| 2047 | + <option value="">Auto</option> | |
| 2048 | + <option value="1K">1K</option> | |
| 2049 | + <option value="2K">2K</option> | |
| 2050 | + <option value="4K">4K</option> | |
| 2051 | + </select> | |
| 2052 | + </div> | |
| 2053 | + <div class="flex1"> | |
| 2054 | + <label for="request_image_aspect_ratio"> | |
| 2055 | + <small data-i18n="Aspect Ratio">Aspect Ratio</small> | |
| 2056 | + </label> | |
| 2057 | + <select id="request_image_aspect_ratio" class="text_pole"> | |
| 2058 | + <option value="">Auto</option> | |
| 2059 | + <option value="1:1">1:1</option> | |
| 2060 | + <option value="9:16">9:16</option> | |
| 2061 | + <option value="16:9">16:9</option> | |
| 2062 | + <option value="3:4">3:4</option> | |
| 2063 | + <option value="4:3">4:3</option> | |
| 2064 | + <option value="3:2">3:2</option> | |
| 2065 | + <option value="2:3">2:3</option> | |
| 2066 | + <option value="5:4">5:4</option> | |
| 2067 | + <option value="4:5">4:5</option> | |
| 2068 | + <option value="21:9">21:9</option> | |
| 2069 | + </select> | |
| 2070 | + </div> | |
| 2071 | + </div> | |
| 2041 | 2072 | </div> |
| 2042 | 2073 | <div class="range-block" data-source="deepseek,aimlapi,openrouter,custom,claude,xai,makersuite,vertexai,pollinations,moonshot,mistralai,fireworks,cometapi,electronhub,azure_openai,nanogpt,zai"> |
| 2043 | 2074 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> |
| @@ -355,6 +355,8 @@ export const settingsToUpdate = { | ||
| 355 | 355 | n: ['#n_openai', 'n', false, false], |
| 356 | 356 | bypass_status_check: ['#openai_bypass_status_check', 'bypass_status_check', true, true], |
| 357 | 357 | request_images: ['#openai_request_images', 'request_images', true, false], |
| 358 | + request_image_aspect_ratio: ['#request_image_aspect_ratio', 'request_image_aspect_ratio', false, false], | |
| 359 | + request_image_resolution: ['#request_image_resolution', 'request_image_resolution', false, false], | |
| 358 | 360 | azure_base_url: ['#azure_base_url', 'azure_base_url', false, true], |
| 359 | 361 | azure_deployment_name: ['#azure_deployment_name', 'azure_deployment_name', false, true], |
| 360 | 362 | azure_api_version: ['#azure_api_version', 'azure_api_version', false, true], |
| @@ -453,6 +455,8 @@ const default_settings = { | ||
| 453 | 455 | verbosity: verbosity_levels.auto, |
| 454 | 456 | enable_web_search: false, |
| 455 | 457 | request_images: false, |
| 458 | + request_image_aspect_ratio: '', | |
| 459 | + request_image_resolution: '', | |
| 456 | 460 | seed: -1, |
| 457 | 461 | n: 1, |
| 458 | 462 | bind_preset_to_connection: true, |
| @@ -2330,6 +2334,8 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } = | ||
| 2330 | 2334 | 'reasoning_effort': getReasoningEffort(), |
| 2331 | 2335 | 'enable_web_search': Boolean(oai_settings.enable_web_search), |
| 2332 | 2336 | 'request_images': Boolean(oai_settings.request_images), |
| 2337 | + 'request_image_resolution': String(oai_settings.request_image_resolution), | |
| 2338 | + 'request_image_aspect_ratio': String(oai_settings.request_image_aspect_ratio), | |
| 2333 | 2339 | 'custom_prompt_post_processing': oai_settings.custom_prompt_post_processing, |
| 2334 | 2340 | 'verbosity': getVerbosity(), |
| 2335 | 2341 | }; |
| @@ -6331,6 +6337,16 @@ export function initOpenAI() { | ||
| 6331 | 6337 | saveSettingsDebounced(); |
| 6332 | 6338 | }); |
| 6333 | 6339 | |
| 6340 | + $('#request_image_resolution').on('input', function () { | |
| 6341 | + oai_settings.request_image_resolution = String($(this).val()); | |
| 6342 | + saveSettingsDebounced(); | |
| 6343 | + }); | |
| 6344 | + | |
| 6345 | + $('#request_image_aspect_ratio').on('input', function () { | |
| 6346 | + oai_settings.request_image_aspect_ratio = String($(this).val()); | |
| 6347 | + saveSettingsDebounced(); | |
| 6348 | + }); | |
| 6349 | + | |
| 6334 | 6350 | if (!CSS.supports('field-sizing', 'content')) { |
| 6335 | 6351 | $(document).on('input', '#openai_settings .autoSetHeight', function () { |
| 6336 | 6352 | resetScrollHeight($(this)); |
| @@ -367,6 +367,8 @@ async function sendMakerSuiteRequest(request, response) { | ||
| 367 | 367 | const requestImages = Boolean(request.body.request_images); |
| 368 | 368 | const reasoningEffort = String(request.body.reasoning_effort); |
| 369 | 369 | const includeReasoning = Boolean(request.body.include_reasoning); |
| 370 | + const aspectRatio = String(request.body.request_image_aspect_ratio); | |
| 371 | + const imageSize = String(request.body.request_image_resolution); | |
| 370 | 372 | const isGemma = model.includes('gemma'); |
| 371 | 373 | const isLearnLM = model.includes('learnlm'); |
| 372 | 374 | |
| @@ -397,6 +399,7 @@ async function sendMakerSuiteRequest(request, response) { | ||
| 397 | 399 | ]; |
| 398 | 400 | |
| 399 | 401 | const isThinkingConfigModel = m => (/^gemini-2.5-(flash|pro)/.test(m) && !/-image(-preview)?$/.test(m)) || (/^gemini-3-pro/.test(m)); |
| 402 | + const isImageSizeModel = m => /^gemini-3/.test(m); | |
| 400 | 403 | |
| 401 | 404 | const noSearchModels = [ |
| 402 | 405 | 'gemini-2.0-flash-lite', |
| @@ -411,8 +414,18 @@ async function sendMakerSuiteRequest(request, response) { | ||
| 411 | 414 | } |
| 412 | 415 | |
| 413 | 416 | const enableImageModality = requestImages && imageGenerationModels.includes(model); |
| 417 | + const enableImageConfig = enableImageModality && (aspectRatio || imageSize); | |
| 414 | 418 | if (enableImageModality) { |
| 415 | 419 | generationConfig.responseModalities = ['text', 'image']; |
| 420 | + if (enableImageConfig) { | |
| 421 | + generationConfig.imageConfig = {}; | |
| 422 | + if (imageSize && isImageSizeModel(model)) { | |
| 423 | + generationConfig.imageConfig.imageSize = imageSize; | |
| 424 | + } | |
| 425 | + if (aspectRatio) { | |
| 426 | + generationConfig.imageConfig.aspectRatio = aspectRatio; | |
| 427 | + } | |
| 428 | + } | |
| 416 | 429 | } |
| 417 | 430 | |
| 418 | 431 | const useSystemPrompt = !enableImageModality && !isGemma && request.body.use_sysprompt; |