mirror of
https://github.com/openai/codex.git
synced 2026-09-08 15:50:34 +00:00
Centralize prompt image detail modes (#42624)
## What changed - Add `PromptImageMode::HIGH_DETAIL` and `PromptImageMode::ORIGINAL_DETAIL` constants with the standard resize limits. - Use the shared modes during core image preparation instead of defining the limits locally. - Cover the dimension and patch budgets for both detail modes in the image utility tests. GitOrigin-RevId: 27fdc77719f23d2e8f1060886576b3be843a8491
This commit is contained in:
committed by
copyberry
parent
781c183c3b
commit
280ae8b9fc
@@ -19,7 +19,6 @@ use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
use codex_utils_image::ImageProcessingError;
|
||||
use codex_utils_image::PromptImageMode;
|
||||
use codex_utils_image::PromptImageResizeLimits;
|
||||
use codex_utils_image::load_data_url_for_prompt;
|
||||
use tracing::warn;
|
||||
|
||||
@@ -31,15 +30,6 @@ const UNSUPPORTED_LOW_DETAIL_PLACEHOLDER: &str = "image content omitted because
|
||||
const REMOTE_IMAGE_URL_PLACEHOLDER: &str =
|
||||
"image content omitted because remote image URLs are not supported";
|
||||
|
||||
const HIGH_DETAIL_LIMITS: PromptImageResizeLimits = PromptImageResizeLimits {
|
||||
max_dimension: 2048,
|
||||
max_patches: 2_500,
|
||||
};
|
||||
const UNIFIED_IMAGE_LIMITS: PromptImageResizeLimits = PromptImageResizeLimits {
|
||||
max_dimension: 6000,
|
||||
max_patches: 10_000,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum ImagePreparationMode {
|
||||
DetailBased,
|
||||
@@ -288,17 +278,23 @@ fn prepare_image(
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let (effective_detail, limits) = match mode {
|
||||
ImagePreparationMode::UnifiedBudget => (ImageDetailSetting::Original, UNIFIED_IMAGE_LIMITS),
|
||||
let (effective_detail, image_mode) = match mode {
|
||||
ImagePreparationMode::UnifiedBudget => (
|
||||
ImageDetailSetting::Original,
|
||||
PromptImageMode::ORIGINAL_DETAIL,
|
||||
),
|
||||
ImagePreparationMode::DetailBased => match detail {
|
||||
None | Some(ImageDetail::Auto | ImageDetail::High) => {
|
||||
(ImageDetailSetting::High, HIGH_DETAIL_LIMITS)
|
||||
(ImageDetailSetting::High, PromptImageMode::HIGH_DETAIL)
|
||||
}
|
||||
Some(ImageDetail::Original) => (ImageDetailSetting::Original, UNIFIED_IMAGE_LIMITS),
|
||||
Some(ImageDetail::Original) => (
|
||||
ImageDetailSetting::Original,
|
||||
PromptImageMode::ORIGINAL_DETAIL,
|
||||
),
|
||||
Some(ImageDetail::Low) => return Err(ImagePreparationError::UnsupportedLowDetail),
|
||||
},
|
||||
};
|
||||
let image = load_data_url_for_prompt(image_url, PromptImageMode::ResizeWithLimits(limits))?;
|
||||
let image = load_data_url_for_prompt(image_url, image_mode)?;
|
||||
metadata.push(ImagePreparationMetadata {
|
||||
message_role: origin.message_role.map(str::to_string),
|
||||
item_id: origin.item_id.map(str::to_string),
|
||||
|
||||
@@ -276,31 +276,37 @@ fn data_url_processing_rejects_malformed_input() {
|
||||
}
|
||||
}
|
||||
|
||||
/// The shared detail modes apply the policies used by external byte-oriented callers.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn resize_with_limits_respects_dimension_and_patch_budgets() {
|
||||
let image = ImageBuffer::from_pixel(2048, 2048, Rgba([200u8, 10, 10, 255]));
|
||||
let original_bytes = image_bytes(&image, ImageFormat::Png);
|
||||
let limits = PromptImageResizeLimits {
|
||||
max_dimension: 2048,
|
||||
max_patches: 2_500,
|
||||
};
|
||||
async fn detail_modes_apply_expected_budgets() {
|
||||
for (mode, input_dimensions, expected_dimensions) in [
|
||||
(PromptImageMode::HIGH_DETAIL, (2048, 2048), (1600, 1600)),
|
||||
(PromptImageMode::ORIGINAL_DETAIL, (6401, 100), (6000, 94)),
|
||||
] {
|
||||
let image = ImageBuffer::from_pixel(
|
||||
input_dimensions.0,
|
||||
input_dimensions.1,
|
||||
Rgba([200u8, 10, 10, 255]),
|
||||
);
|
||||
let original_bytes = image_bytes(&image, ImageFormat::Png);
|
||||
let processed = load_for_prompt_bytes(Path::new("in-memory-image"), original_bytes, mode)
|
||||
.expect("process image with detail mode");
|
||||
|
||||
let processed = load_for_prompt_bytes(
|
||||
Path::new("in-memory-image"),
|
||||
original_bytes,
|
||||
PromptImageMode::ResizeWithLimits(limits),
|
||||
)
|
||||
.expect("process image with explicit limits");
|
||||
|
||||
assert_eq!(
|
||||
(
|
||||
processed.source_width,
|
||||
processed.source_height,
|
||||
processed.width,
|
||||
processed.height,
|
||||
),
|
||||
(2048, 2048, 1600, 1600)
|
||||
);
|
||||
assert_eq!(
|
||||
(
|
||||
processed.source_width,
|
||||
processed.source_height,
|
||||
processed.width,
|
||||
processed.height,
|
||||
),
|
||||
(
|
||||
input_dimensions.0,
|
||||
input_dimensions.1,
|
||||
expected_dimensions.0,
|
||||
expected_dimensions.1,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
|
||||
@@ -70,6 +70,19 @@ pub struct PromptImageResizeLimits {
|
||||
pub max_patches: usize,
|
||||
}
|
||||
|
||||
impl PromptImageMode {
|
||||
/// Resize policy for high-detail prompt images.
|
||||
pub const HIGH_DETAIL: Self = Self::ResizeWithLimits(PromptImageResizeLimits {
|
||||
max_dimension: 2048,
|
||||
max_patches: 2_500,
|
||||
});
|
||||
/// Resize policy for original-detail prompt images.
|
||||
pub const ORIGINAL_DETAIL: Self = Self::ResizeWithLimits(PromptImageResizeLimits {
|
||||
max_dimension: 6000,
|
||||
max_patches: 10_000,
|
||||
});
|
||||
}
|
||||
|
||||
struct ImageMetadata {
|
||||
icc_profile: Option<Vec<u8>>,
|
||||
exif: Option<Vec<u8>>,
|
||||
|
||||
Reference in New Issue
Block a user