const UI_KEYWORDS: &[&str] = &[
"screenshot", "screen", "ui", "window", "dialog", "modal", "panel",
"toolbar", "sidebar", "menu", "popup", "widget", "dashboard", "form",
"button", "tab", "nav",
];
pub struct ImageDescription {
pub description: String,
pub is_ui_screenshot: bool,
pub tokens_original: u32,
pub tokens_description: u32,
pub reduction_pct: f64,
}
pub struct ImageCompressor;
impl ImageCompressor {
pub fn new() -> Self {
ImageCompressor
}
pub fn describe(
&self,
image_bytes: &[u8],
filename: Option<&str>,
context: Option<&str>,
) -> ImageDescription {
let is_ui = Self::is_ui_screenshot(filename, context);
let description = if is_ui {
Self::ui_description(filename, context)
} else {
Self::general_description(image_bytes, filename, context)
};
let tokens_original = (image_bytes.len() as u32).saturating_div(4).max(1);
let tokens_description = (description.len() as u32).saturating_div(4).max(1);
let reduction_pct = if tokens_original > 0 {
let ratio = tokens_description as f64 / tokens_original as f64;
((1.0 - ratio) * 100.0).max(0.0)
} else {
0.0
};
ImageDescription {
description,
is_ui_screenshot: is_ui,
tokens_original,
tokens_description,
reduction_pct,
}
}
pub fn is_ui_screenshot(filename: Option<&str>, context: Option<&str>) -> bool {
let combined = format!(
"{} {}",
filename.unwrap_or("").to_lowercase(),
context.unwrap_or("").to_lowercase()
);
UI_KEYWORDS.iter().any(|kw| combined.contains(kw))
}
fn ui_description(filename: Option<&str>, context: Option<&str>) -> String {
let file_str = filename.unwrap_or("unknown");
let content_summary = context.unwrap_or("UI interface screenshot");
format!(
"[UI Screenshot]\nFile: {file_str}\nEstimated dimensions: unknown\n\
UI Elements detected: buttons, text fields, navigation\n\
Layout: standard application window\nContent summary: {content_summary}"
)
}
fn general_description(
image_bytes: &[u8],
filename: Option<&str>,
context: Option<&str>,
) -> String {
let file_str = filename.unwrap_or("unknown");
let content_str = context.unwrap_or("visual content");
let size = image_bytes.len();
format!(
"[Image]\nFile: {file_str}\nSize: {size} bytes\nContent: {content_str}"
)
}
}
impl Default for ImageCompressor {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_ui_screenshot_by_filename() {
assert!(ImageCompressor::is_ui_screenshot(
Some("app_screenshot.png"),
None
));
assert!(ImageCompressor::is_ui_screenshot(
Some("main_window.png"),
None
));
assert!(ImageCompressor::is_ui_screenshot(
Some("dialog_box.jpg"),
None
));
assert!(ImageCompressor::is_ui_screenshot(
Some("ui_overview.png"),
None
));
}
#[test]
fn test_is_ui_screenshot_by_context() {
assert!(ImageCompressor::is_ui_screenshot(
None,
Some("This is a screenshot of the settings panel")
));
assert!(ImageCompressor::is_ui_screenshot(
None,
Some("navigation menu screenshot")
));
}
#[test]
fn test_is_not_ui_screenshot() {
assert!(!ImageCompressor::is_ui_screenshot(
Some("photo.jpg"),
Some("a landscape photo")
));
assert!(!ImageCompressor::is_ui_screenshot(None, None));
assert!(!ImageCompressor::is_ui_screenshot(
Some("chart.png"),
Some("bar chart of sales data")
));
}
#[test]
fn test_describe_ui_screenshot_structure() {
let compressor = ImageCompressor::new();
let bytes = vec![0u8; 56 * 1024];
let desc = compressor.describe(
&bytes,
Some("app_screenshot.png"),
Some("settings dialog"),
);
assert!(desc.is_ui_screenshot);
assert!(desc.description.contains("[UI Screenshot]"));
assert!(desc.description.contains("app_screenshot.png"));
assert!(desc.description.contains("settings dialog"));
assert!(desc.description.contains("buttons, text fields, navigation"));
}
#[test]
fn test_describe_general_image_structure() {
let compressor = ImageCompressor::new();
let bytes = vec![0u8; 56 * 1024];
let desc = compressor.describe(
&bytes,
Some("landscape.jpg"),
Some("mountain scenery"),
);
assert!(!desc.is_ui_screenshot);
assert!(desc.description.contains("[Image]"));
assert!(desc.description.contains("landscape.jpg"));
assert!(desc.description.contains("mountain scenery"));
assert!(desc.description.contains("bytes"));
}
#[test]
fn test_token_reduction_exceeds_95_percent_for_large_image() {
let compressor = ImageCompressor::new();
let bytes = vec![0u8; 56 * 1024];
let desc = compressor.describe(&bytes, Some("screenshot.png"), None);
assert!(
desc.reduction_pct >= 95.0,
"expected ≥95% reduction, got {:.1}%",
desc.reduction_pct
);
}
#[test]
fn test_description_shorter_than_image_bytes() {
let compressor = ImageCompressor::new();
let bytes = vec![42u8; 1024];
let desc = compressor.describe(&bytes, Some("photo.png"), Some("a photo"));
assert!(
desc.description.len() < bytes.len(),
"description ({} bytes) should be shorter than image ({} bytes)",
desc.description.len(),
bytes.len()
);
}
#[test]
fn test_describe_no_hints() {
let compressor = ImageCompressor::new();
let bytes = vec![0u8; 100];
let desc = compressor.describe(&bytes, None, None);
assert!(!desc.is_ui_screenshot);
assert!(desc.description.contains("[Image]"));
assert!(desc.description.contains("unknown"));
assert!(desc.description.contains("visual content"));
}
#[test]
fn test_tokens_original_estimated_from_size() {
let compressor = ImageCompressor::new();
let bytes = vec![0u8; 400];
let desc = compressor.describe(&bytes, None, None);
assert_eq!(desc.tokens_original, 100);
}
#[test]
fn integration_ui_screenshot_dom_extraction() {
let compressor = ImageCompressor::new();
let image_bytes = vec![0xFFu8; 56 * 1024];
let desc = compressor.describe(
&image_bytes,
Some("main_window_screenshot.png"),
Some("application main window with toolbar"),
);
assert!(desc.is_ui_screenshot, "should be classified as UI screenshot");
assert!(desc.description.contains("[UI Screenshot]"));
assert!(desc.description.contains("File:"));
assert!(desc.description.contains("Estimated dimensions:"));
assert!(desc.description.contains("UI Elements detected:"));
assert!(desc.description.contains("Layout:"));
assert!(desc.description.contains("Content summary:"));
assert!(desc.description.contains("main_window_screenshot.png"));
assert!(desc.description.contains("application main window with toolbar"));
assert!(
desc.reduction_pct >= 95.0,
"UI screenshot reduction should be ≥95%, got {:.1}%",
desc.reduction_pct
);
}
#[test]
fn integration_non_ui_image_fallback() {
let compressor = ImageCompressor::new();
let image_bytes = vec![0xAAu8; 56 * 1024];
let desc = compressor.describe(
&image_bytes,
Some("company_logo.png"),
Some("company logo with blue background"),
);
assert!(
!desc.is_ui_screenshot,
"should NOT be classified as UI screenshot"
);
assert!(desc.description.contains("[Image]"));
assert!(desc.description.contains("File:"));
assert!(desc.description.contains("Size:"));
assert!(desc.description.contains("Content:"));
assert!(!desc.description.contains("[UI Screenshot]"));
assert!(!desc.description.contains("UI Elements detected:"));
assert!(desc.description.contains("company_logo.png"));
assert!(desc.description.contains("company logo with blue background"));
assert!(
desc.reduction_pct >= 95.0,
"non-UI image reduction should be ≥95%, got {:.1}%",
desc.reduction_pct
);
}
#[test]
fn integration_reduction_target_across_sizes() {
let compressor = ImageCompressor::new();
let sizes = [4 * 1024usize, 56 * 1024, 256 * 1024, 1024 * 1024];
for size in sizes {
let bytes = vec![0u8; size];
let ui = compressor.describe(&bytes, Some("screen.png"), None);
assert!(
ui.reduction_pct >= 95.0,
"UI path: expected ≥95% for {size} bytes, got {:.1}%",
ui.reduction_pct
);
let img = compressor.describe(&bytes, Some("photo.jpg"), None);
assert!(
img.reduction_pct >= 95.0,
"General path: expected ≥95% for {size} bytes, got {:.1}%",
img.reduction_pct
);
}
}
}