feat(billing): add image quality pricing and usage tracking

This commit is contained in:
ZheFox
2026-05-18 00:11:30 +08:00
parent 680b617b00
commit c024c782e4
13 changed files with 559 additions and 12 deletions

View File

@@ -816,6 +816,11 @@ fn openai_image_stream_standardized_usage(
.dimensions
.insert("image_size".to_string(), serde_json::json!(size));
}
if let Some(quality) = image_request_quality(report_context) {
standardized_usage
.dimensions
.insert("image_quality".to_string(), serde_json::json!(quality));
}
(standardized_usage.signal_score() > 0).then_some(standardized_usage)
}
@@ -1049,6 +1054,16 @@ fn image_request_size(report_context: Option<&Value>) -> Option<String> {
.map(ToOwned::to_owned)
}
fn image_request_quality(report_context: Option<&Value>) -> Option<String> {
report_context
.and_then(|value| value.get("image_request"))
.and_then(|value| value.get("quality"))
.and_then(Value::as_str)
.map(str::trim)
.filter(|value| !value.is_empty())
.map(ToOwned::to_owned)
}
fn image_bridge_model(report_context: Option<&Value>) -> Option<String> {
report_context.and_then(|context| {
context

View File

@@ -978,6 +978,7 @@ mod tests {
let mut report_context = report_context("openai:image", "openai:chat");
report_context["image_request"] = json!({
"size": "1024x1024",
"quality": "medium",
"output_format": "png",
});
let mut observer = StreamingStandardTerminalObserver::default();
@@ -1048,5 +1049,9 @@ mod tests {
usage.dimensions.get("image_output_format"),
Some(&json!("png"))
);
assert_eq!(
usage.dimensions.get("image_quality"),
Some(&json!("medium"))
);
}
}

View File

@@ -471,6 +471,11 @@ fn openai_image_standardized_usage(
.dimensions
.insert("image_size".to_string(), json!(size));
}
if let Some(quality) = image_request_quality(report_context) {
standardized_usage
.dimensions
.insert("image_quality".to_string(), json!(quality));
}
(standardized_usage.signal_score() > 0).then_some(standardized_usage)
}
@@ -546,6 +551,16 @@ fn image_request_size(report_context: Option<&Value>) -> Option<String> {
.map(ToOwned::to_owned)
}
fn image_request_quality(report_context: Option<&Value>) -> Option<String> {
report_context
.and_then(|value| value.get("image_request"))
.and_then(|value| value.get("quality"))
.and_then(Value::as_str)
.map(str::trim)
.filter(|value| !value.is_empty())
.map(ToOwned::to_owned)
}
fn mime_type_from_image_output_format(output_format: &str) -> String {
match output_format.trim().to_ascii_lowercase().as_str() {
"jpg" | "jpeg" => "image/jpeg".to_string(),
@@ -999,7 +1014,8 @@ mod tests {
"image_request": {
"operation": "generate",
"output_format": "png",
"size": "1024x1024"
"size": "1024x1024",
"quality": "medium"
}
});
let outcome = maybe_bridge_standard_sync_json_to_stream(
@@ -1045,6 +1061,10 @@ mod tests {
usage.dimensions.get("image_size"),
Some(&json!("1024x1024"))
);
assert_eq!(
usage.dimensions.get("image_quality"),
Some(&json!("medium"))
);
}
#[test]