fix: log VectorEngine image edit request params

This commit is contained in:
kdletters
2026-06-04 01:22:28 +08:00
parent ef236fc3a7
commit 2678954627
4 changed files with 144 additions and 4 deletions

View File

@@ -5,7 +5,8 @@ use super::{
error::PlatformImageError,
image_source::resolve_reference_images,
request::{
build_prompt_with_negative, build_vector_engine_image_request_body, normalize_image_size,
build_prompt_with_negative, build_vector_engine_image_edit_request_log_params,
build_vector_engine_image_request_body, normalize_image_size,
vector_engine_images_edit_url, vector_engine_images_generation_url,
},
response::handle_vector_engine_response,
@@ -71,6 +72,7 @@ pub async fn create_vector_engine_image_generation(
started_at.elapsed().as_millis() as u64,
Some(prompt.chars().count()),
Some(reference_images.len()),
Some(&request_body),
));
}
};
@@ -97,6 +99,7 @@ pub async fn create_vector_engine_image_generation(
started_at.elapsed().as_millis() as u64,
Some(prompt.chars().count()),
Some(reference_images.len()),
Some(&request_body),
));
}
};
@@ -156,6 +159,13 @@ pub async fn create_vector_engine_image_edit_with_references(
let request_url = vector_engine_images_edit_url(settings);
let normalized_size = normalize_image_size(size);
let request_params = build_vector_engine_image_edit_request_log_params(
prompt,
negative_prompt,
normalized_size.as_str(),
candidate_count,
reference_images,
);
let mut form = reqwest::multipart::Form::new()
.text("model", GPT_IMAGE_2_MODEL.to_string())
@@ -178,7 +188,32 @@ pub async fn create_vector_engine_image_edit_with_references(
}
let reference_image_count = reference_images.iter().take(5).count();
let reference_image_bytes_total: usize = reference_images
.iter()
.take(5)
.map(|image| image.bytes.len())
.sum();
let started_at = std::time::Instant::now();
tracing::info!(
provider = VECTOR_ENGINE_PROVIDER,
endpoint = %request_url,
image_model = GPT_IMAGE_2_MODEL,
size = %normalized_size,
candidate_count = candidate_count.clamp(1, 4),
requested_candidate_count = candidate_count,
prompt_chars = prompt.trim().chars().count(),
negative_prompt_chars = negative_prompt
.map(str::trim)
.filter(|value| !value.is_empty())
.map(str::chars)
.map(Iterator::count)
.unwrap_or_default(),
reference_image_count,
reference_image_bytes_total,
request_params = %request_params,
failure_context,
"VectorEngine 图片编辑请求参数"
);
let response = match http_client
.post(request_url.as_str())
.header(
@@ -200,6 +235,7 @@ pub async fn create_vector_engine_image_edit_with_references(
started_at.elapsed().as_millis() as u64,
Some(prompt.chars().count()),
Some(reference_image_count),
Some(&request_params),
));
}
};
@@ -211,6 +247,8 @@ pub async fn create_vector_engine_image_edit_with_references(
prompt_chars = prompt.chars().count(),
size = %normalized_size,
reference_image_count,
reference_image_bytes_total,
request_params = %request_params,
elapsed_ms = started_at.elapsed().as_millis() as u64,
failure_context,
"VectorEngine 图片编辑 HTTP 返回"
@@ -226,6 +264,7 @@ pub async fn create_vector_engine_image_edit_with_references(
started_at.elapsed().as_millis() as u64,
Some(prompt.chars().count()),
Some(reference_image_count),
Some(&request_params),
));
}
};

View File

@@ -1,6 +1,9 @@
use serde_json::{Map, Value, json};
use super::{constants::GPT_IMAGE_2_MODEL, types::VectorEngineImageSettings};
use super::{
constants::GPT_IMAGE_2_MODEL,
types::{ReferenceImage, VectorEngineImageSettings},
};
pub fn build_vector_engine_image_request_body(
prompt: &str,
@@ -56,6 +59,52 @@ pub fn vector_engine_images_edit_url(settings: &VectorEngineImageSettings) -> St
}
}
pub(crate) fn build_vector_engine_image_edit_request_log_params(
prompt: &str,
negative_prompt: Option<&str>,
size: &str,
candidate_count: u32,
reference_images: &[ReferenceImage],
) -> Value {
let prompt = prompt.trim();
let negative_prompt = negative_prompt
.map(str::trim)
.filter(|value| !value.is_empty());
let references: Vec<Value> = reference_images
.iter()
.take(5)
.enumerate()
.map(|(index, image)| {
json!({
"index": index,
"field": "image",
"fileName": image.file_name.as_str(),
"mimeType": image.mime_type.as_str(),
"bytes": image.bytes.len(),
})
})
.collect();
let reference_image_bytes_total: usize = reference_images
.iter()
.take(5)
.map(|image| image.bytes.len())
.sum();
json!({
"model": GPT_IMAGE_2_MODEL,
"prompt": prompt,
"negativePrompt": negative_prompt.unwrap_or_default(),
"promptChars": prompt.chars().count(),
"negativePromptChars": negative_prompt.map(str::chars).map(Iterator::count),
"n": candidate_count.clamp(1, 4),
"requestedCandidateCount": candidate_count,
"size": size,
"referenceImageCount": references.len(),
"referenceImageBytesTotal": reference_image_bytes_total,
"referenceImages": references,
})
}
pub(crate) fn build_prompt_with_negative(prompt: &str, negative_prompt: Option<&str>) -> String {
let prompt = prompt.trim();
let Some(negative_prompt) = negative_prompt
@@ -67,3 +116,49 @@ pub(crate) fn build_prompt_with_negative(prompt: &str, negative_prompt: Option<&
format!("{prompt}\n避免:{negative_prompt}")
}
#[cfg(test)]
mod tests {
use super::*;
use crate::vector_engine::types::ReferenceImage;
#[test]
fn edit_request_log_params_include_reference_image_sizes_without_secrets_or_bytes() {
let params = build_vector_engine_image_edit_request_log_params(
" 拼图参考图重绘 ",
Some(" 文字,水印 "),
"1024x1024",
9,
&[
ReferenceImage {
bytes: vec![1, 2, 3, 4, 5],
mime_type: "image/png".to_string(),
file_name: "reference-a.png".to_string(),
},
ReferenceImage {
bytes: vec![8; 7],
mime_type: "image/jpeg".to_string(),
file_name: "reference-b.jpg".to_string(),
},
],
);
assert_eq!(params["model"], GPT_IMAGE_2_MODEL);
assert_eq!(params["prompt"], "拼图参考图重绘");
assert_eq!(params["negativePrompt"], "文字,水印");
assert_eq!(params["n"], 4);
assert_eq!(params["requestedCandidateCount"], 9);
assert_eq!(params["size"], "1024x1024");
assert_eq!(params["referenceImageCount"], 2);
assert_eq!(params["referenceImageBytesTotal"], 12);
assert_eq!(params["referenceImages"][0]["field"], "image");
assert_eq!(params["referenceImages"][0]["fileName"], "reference-a.png");
assert_eq!(params["referenceImages"][0]["mimeType"], "image/png");
assert_eq!(params["referenceImages"][0]["bytes"], 5);
let serialized = params.to_string();
assert!(!serialized.contains("api_key"));
assert!(!serialized.contains("Bearer"));
assert!(!serialized.contains("[1,2,3,4,5]"));
}
}

View File

@@ -1,5 +1,7 @@
use std::{error::Error, time::Duration};
use serde_json::Value;
use super::{
audit::build_failure_audit, constants::VECTOR_ENGINE_PROVIDER, error::PlatformImageError,
types::VectorEngineImageSettings,
@@ -27,6 +29,7 @@ pub(super) fn map_reqwest_error(
latency_ms: u64,
prompt_chars: Option<usize>,
reference_image_count: Option<usize>,
request_params: Option<&Value>,
) -> PlatformImageError {
let is_timeout = error.is_timeout();
let is_connect = error.is_connect();
@@ -70,6 +73,9 @@ pub(super) fn map_reqwest_error(
elapsed_ms = latency_ms,
prompt_chars,
reference_image_count,
request_params = %request_params
.map(|value| value.to_string())
.unwrap_or_default(),
"VectorEngine 图片请求发送失败"
);