Gemini: Add image request settings (#4838) * Gemini: Add image request settings * Allow aspect ratio for 2.5 flash

2eba10fa7f8fcf8f2783a6cdd85ec269b237412f

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
4 files changed, +65 -1Ignore whitespace
public/css/toggle-dependent.css+4 -0
@@ -563,3 +563,7 @@ label[for="bind_preset_to_connection"]:has(input:checked) {
563 filter: grayscale(0.5);563 filter: grayscale(0.5);
564 cursor: not-allowed;564 cursor: not-allowed;
565}565}
566
567#request_images_block:has(#openai_request_images:not(:checked)) #request_images_settings {
568 display: none;
569}
public/index.html+32 -1
@@ -2022,7 +2022,7 @@
2022 </div>2022 </div>
2023 </div>2023 </div>
2024 </div>2024 </div>
2025 <div class="range-block" data-source="makersuite,vertexai">2025 <div id="request_images_block" class="range-block" data-source="makersuite,vertexai">
2026 <label for="openai_request_images" class="checkbox_label widthFreeExpand">2026 <label for="openai_request_images" class="checkbox_label widthFreeExpand">
2027 <input id="openai_request_images" type="checkbox" />2027 <input id="openai_request_images" type="checkbox" />
2028 <span>2028 <span>
@@ -2038,6 +2038,37 @@
2038 Incompatible with the following features: function calling, web search, system prompt.2038 Incompatible with the following features: function calling, web search, system prompt.
2039 </em>2039 </em>
2040 </div>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 </div>2072 </div>
2042 <div class="range-block" data-source="deepseek,aimlapi,openrouter,custom,claude,xai,makersuite,vertexai,pollinations,moonshot,mistralai,fireworks,cometapi,electronhub,azure_openai,nanogpt,zai">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 <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">2074 <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">
public/scripts/openai.js+16 -0
@@ -355,6 +355,8 @@ export const settingsToUpdate = {
355 n: ['#n_openai', 'n', false, false],355 n: ['#n_openai', 'n', false, false],
356 bypass_status_check: ['#openai_bypass_status_check', 'bypass_status_check', true, true],356 bypass_status_check: ['#openai_bypass_status_check', 'bypass_status_check', true, true],
357 request_images: ['#openai_request_images', 'request_images', true, false],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 azure_base_url: ['#azure_base_url', 'azure_base_url', false, true],360 azure_base_url: ['#azure_base_url', 'azure_base_url', false, true],
359 azure_deployment_name: ['#azure_deployment_name', 'azure_deployment_name', false, true],361 azure_deployment_name: ['#azure_deployment_name', 'azure_deployment_name', false, true],
360 azure_api_version: ['#azure_api_version', 'azure_api_version', false, true],362 azure_api_version: ['#azure_api_version', 'azure_api_version', false, true],
@@ -453,6 +455,8 @@ const default_settings = {
453 verbosity: verbosity_levels.auto,455 verbosity: verbosity_levels.auto,
454 enable_web_search: false,456 enable_web_search: false,
455 request_images: false,457 request_images: false,
458 request_image_aspect_ratio: '',
459 request_image_resolution: '',
456 seed: -1,460 seed: -1,
457 n: 1,461 n: 1,
458 bind_preset_to_connection: true,462 bind_preset_to_connection: true,
@@ -2330,6 +2334,8 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } =
2330 'reasoning_effort': getReasoningEffort(),2334 'reasoning_effort': getReasoningEffort(),
2331 'enable_web_search': Boolean(oai_settings.enable_web_search),2335 'enable_web_search': Boolean(oai_settings.enable_web_search),
2332 'request_images': Boolean(oai_settings.request_images),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 'custom_prompt_post_processing': oai_settings.custom_prompt_post_processing,2339 'custom_prompt_post_processing': oai_settings.custom_prompt_post_processing,
2334 'verbosity': getVerbosity(),2340 'verbosity': getVerbosity(),
2335 };2341 };
@@ -6331,6 +6337,16 @@ export function initOpenAI() {
6331 saveSettingsDebounced();6337 saveSettingsDebounced();
6332 });6338 });
63336339
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 if (!CSS.supports('field-sizing', 'content')) {6350 if (!CSS.supports('field-sizing', 'content')) {
6335 $(document).on('input', '#openai_settings .autoSetHeight', function () {6351 $(document).on('input', '#openai_settings .autoSetHeight', function () {
6336 resetScrollHeight($(this));6352 resetScrollHeight($(this));
src/endpoints/backends/chat-completions.js+13 -0
@@ -367,6 +367,8 @@ async function sendMakerSuiteRequest(request, response) {
367 const requestImages = Boolean(request.body.request_images);367 const requestImages = Boolean(request.body.request_images);
368 const reasoningEffort = String(request.body.reasoning_effort);368 const reasoningEffort = String(request.body.reasoning_effort);
369 const includeReasoning = Boolean(request.body.include_reasoning);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 const isGemma = model.includes('gemma');372 const isGemma = model.includes('gemma');
371 const isLearnLM = model.includes('learnlm');373 const isLearnLM = model.includes('learnlm');
372374
@@ -397,6 +399,7 @@ async function sendMakerSuiteRequest(request, response) {
397 ];399 ];
398400
399 const isThinkingConfigModel = m => (/^gemini-2.5-(flash|pro)/.test(m) && !/-image(-preview)?$/.test(m)) || (/^gemini-3-pro/.test(m));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);
400403
401 const noSearchModels = [404 const noSearchModels = [
402 'gemini-2.0-flash-lite',405 'gemini-2.0-flash-lite',
@@ -411,8 +414,18 @@ async function sendMakerSuiteRequest(request, response) {
411 }414 }
412415
413 const enableImageModality = requestImages && imageGenerationModels.includes(model);416 const enableImageModality = requestImages && imageGenerationModels.includes(model);
417 const enableImageConfig = enableImageModality && (aspectRatio || imageSize);
414 if (enableImageModality) {418 if (enableImageModality) {
415 generationConfig.responseModalities = ['text', 'image'];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 }
417430
418 const useSystemPrompt = !enableImageModality && !isGemma && request.body.use_sysprompt;431 const useSystemPrompt = !enableImageModality && !isGemma && request.body.use_sysprompt;