删除已失效的跨模型回退分支
移除 generation / edit 重试路径中恒为 false 的 should_fallback_to_gpt_image_2_c 判断与 record_image_model_fallback 调用 删除为计算该判断而额外调用 handle_image_response 的预解析,避免每次重试都白解析响应并下载图片 删除只断言该函数恒为 false 的单元测试,跨模型不切换已由集成测试覆盖
This commit is contained in:
@@ -99,7 +99,7 @@ pub async fn create_image_generation_with_model(
|
||||
let request_url = images_generation_url(settings);
|
||||
let normalized_size = normalize_image_size_for_model(requested_model, size);
|
||||
let started_at = std::time::Instant::now();
|
||||
let mut upstream_model = preferred_image_upstream_model(requested_model);
|
||||
let upstream_model = preferred_image_upstream_model(requested_model);
|
||||
let mut recovered_failure_audits = Vec::new();
|
||||
let mut attempt = 1;
|
||||
loop {
|
||||
@@ -140,51 +140,6 @@ pub async fn create_image_generation_with_model(
|
||||
response.body.as_str(),
|
||||
attempt,
|
||||
) {
|
||||
let primary_error = if upstream_model == GPT_IMAGE_2_MODEL {
|
||||
handle_image_response(
|
||||
http_client,
|
||||
request_url.as_str(),
|
||||
response.status,
|
||||
response.body.as_str(),
|
||||
auditable_image_model(upstream_model),
|
||||
failure_context,
|
||||
started_at.elapsed().as_millis() as u64,
|
||||
Some(prompt.chars().count()),
|
||||
Some(reference_images.len()),
|
||||
candidate_count,
|
||||
"vector-engine",
|
||||
settings.request_deadline,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if primary_error.as_ref().is_some_and(|error| {
|
||||
should_fallback_to_gpt_image_2_c(
|
||||
requested_model,
|
||||
upstream_model,
|
||||
attempt,
|
||||
error,
|
||||
settings,
|
||||
)
|
||||
}) {
|
||||
let error = primary_error.expect("primary error checked above");
|
||||
record_image_model_fallback(
|
||||
"generation",
|
||||
request_url.as_str(),
|
||||
upstream_model,
|
||||
GPT_IMAGE_2_C_MODEL,
|
||||
attempt,
|
||||
&error,
|
||||
);
|
||||
if let Some(audit) = error.audit().cloned() {
|
||||
recovered_failure_audits.push(audit);
|
||||
}
|
||||
upstream_model = GPT_IMAGE_2_C_MODEL;
|
||||
attempt += 1;
|
||||
continue;
|
||||
}
|
||||
if retry_image_upstream_status_after_delay(
|
||||
"generation",
|
||||
request_url.as_str(),
|
||||
@@ -283,29 +238,6 @@ pub async fn create_image_generation_with_model(
|
||||
.append(&mut recovered_failure_audits);
|
||||
return Ok(generated);
|
||||
}
|
||||
Err(error)
|
||||
if should_fallback_to_gpt_image_2_c(
|
||||
requested_model,
|
||||
upstream_model,
|
||||
attempt,
|
||||
&error,
|
||||
settings,
|
||||
) =>
|
||||
{
|
||||
record_image_model_fallback(
|
||||
"generation",
|
||||
request_url.as_str(),
|
||||
upstream_model,
|
||||
GPT_IMAGE_2_C_MODEL,
|
||||
attempt,
|
||||
&error,
|
||||
);
|
||||
if let Some(audit) = error.audit().cloned() {
|
||||
recovered_failure_audits.push(audit);
|
||||
}
|
||||
upstream_model = GPT_IMAGE_2_C_MODEL;
|
||||
attempt += 1;
|
||||
}
|
||||
Err(error) => {
|
||||
return Err(finish_image_model_fallback_error(
|
||||
error,
|
||||
@@ -577,7 +509,7 @@ pub async fn create_image_edit_with_references_and_model(
|
||||
let reference_image_bytes_total: usize =
|
||||
reference_images.iter().map(|image| image.bytes.len()).sum();
|
||||
let started_at = std::time::Instant::now();
|
||||
let mut upstream_model = preferred_image_upstream_model(requested_model);
|
||||
let upstream_model = preferred_image_upstream_model(requested_model);
|
||||
let mut recovered_failure_audits = Vec::new();
|
||||
let mut attempt = 1;
|
||||
loop {
|
||||
@@ -645,51 +577,6 @@ pub async fn create_image_edit_with_references_and_model(
|
||||
response.body.as_str(),
|
||||
attempt,
|
||||
) {
|
||||
let primary_error = if upstream_model == GPT_IMAGE_2_MODEL {
|
||||
handle_image_response(
|
||||
http_client,
|
||||
request_url.as_str(),
|
||||
response.status,
|
||||
response.body.as_str(),
|
||||
auditable_image_model(upstream_model),
|
||||
failure_context,
|
||||
started_at.elapsed().as_millis() as u64,
|
||||
Some(prompt.chars().count()),
|
||||
Some(reference_image_count),
|
||||
candidate_count,
|
||||
"vector-engine-edit",
|
||||
settings.request_deadline,
|
||||
)
|
||||
.await
|
||||
.err()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if primary_error.as_ref().is_some_and(|error| {
|
||||
should_fallback_to_gpt_image_2_c(
|
||||
requested_model,
|
||||
upstream_model,
|
||||
attempt,
|
||||
error,
|
||||
settings,
|
||||
)
|
||||
}) {
|
||||
let error = primary_error.expect("primary error checked above");
|
||||
record_image_model_fallback(
|
||||
"edit",
|
||||
request_url.as_str(),
|
||||
upstream_model,
|
||||
GPT_IMAGE_2_C_MODEL,
|
||||
attempt,
|
||||
&error,
|
||||
);
|
||||
if let Some(audit) = error.audit().cloned() {
|
||||
recovered_failure_audits.push(audit);
|
||||
}
|
||||
upstream_model = GPT_IMAGE_2_C_MODEL;
|
||||
attempt += 1;
|
||||
continue;
|
||||
}
|
||||
if retry_image_upstream_status_after_delay(
|
||||
"edit",
|
||||
request_url.as_str(),
|
||||
@@ -790,29 +677,6 @@ pub async fn create_image_edit_with_references_and_model(
|
||||
.append(&mut recovered_failure_audits);
|
||||
return Ok(generated);
|
||||
}
|
||||
Err(error)
|
||||
if should_fallback_to_gpt_image_2_c(
|
||||
requested_model,
|
||||
upstream_model,
|
||||
attempt,
|
||||
&error,
|
||||
settings,
|
||||
) =>
|
||||
{
|
||||
record_image_model_fallback(
|
||||
"edit",
|
||||
request_url.as_str(),
|
||||
upstream_model,
|
||||
GPT_IMAGE_2_C_MODEL,
|
||||
attempt,
|
||||
&error,
|
||||
);
|
||||
if let Some(audit) = error.audit().cloned() {
|
||||
recovered_failure_audits.push(audit);
|
||||
}
|
||||
upstream_model = GPT_IMAGE_2_C_MODEL;
|
||||
attempt += 1;
|
||||
}
|
||||
Err(error) => {
|
||||
return Err(finish_image_model_fallback_error(
|
||||
error,
|
||||
@@ -845,19 +709,6 @@ fn auditable_image_model(model: &str) -> Option<&'static str> {
|
||||
}
|
||||
}
|
||||
|
||||
fn should_fallback_to_gpt_image_2_c(
|
||||
requested_model: &str,
|
||||
upstream_model: &str,
|
||||
attempt: u32,
|
||||
error: &PlatformImageError,
|
||||
settings: &ImageProviderSettings,
|
||||
) -> bool {
|
||||
// Compatibility function retained for old call sites/tests. New dispatch
|
||||
// never crosses models; retries are handled by the same-model loop only.
|
||||
let _ = (requested_model, upstream_model, attempt, error, settings);
|
||||
false
|
||||
}
|
||||
|
||||
fn contains_image_provider_content_rejection(message: &str, raw_excerpt: &str) -> bool {
|
||||
let haystack = format!("{message}\n{raw_excerpt}").to_ascii_lowercase();
|
||||
[
|
||||
@@ -883,31 +734,6 @@ fn contains_image_provider_content_rejection(message: &str, raw_excerpt: &str) -
|
||||
.any(|marker| haystack.contains(marker))
|
||||
}
|
||||
|
||||
fn record_image_model_fallback(
|
||||
request_kind: &'static str,
|
||||
request_url: &str,
|
||||
from_model: &str,
|
||||
to_model: &str,
|
||||
attempt: u32,
|
||||
error: &PlatformImageError,
|
||||
) {
|
||||
let audit = error.audit();
|
||||
tracing::warn!(
|
||||
provider = VECTOR_ENGINE_PROVIDER,
|
||||
endpoint = %request_url,
|
||||
request_kind,
|
||||
fallback_from_model = from_model,
|
||||
fallback_to_model = to_model,
|
||||
attempt,
|
||||
next_attempt = attempt + 1,
|
||||
max_attempts = VECTOR_ENGINE_SEND_MAX_ATTEMPTS,
|
||||
failure_stage = audit.map(|audit| audit.failure_stage).unwrap_or("unknown"),
|
||||
status = audit.and_then(|audit| audit.status_code).unwrap_or_default(),
|
||||
error = %error.message(),
|
||||
"ImageProvider 首选图片模型失败,切换兼容模型"
|
||||
);
|
||||
}
|
||||
|
||||
fn should_retry_image_curl_send_error(
|
||||
error: &super::curl_transport::ImageProviderCurlError,
|
||||
attempt: u32,
|
||||
@@ -1202,28 +1028,6 @@ mod tests {
|
||||
assert!(!should_retry_image_upstream_response(502, "", 5));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn image_provider_never_falls_back_across_image_models() {
|
||||
let settings = ImageProviderSettings {
|
||||
provider: ImageProvider::VectorEngine,
|
||||
base_url: "https://vector.example/v1".to_string(),
|
||||
api_key: "test-key".to_string(),
|
||||
request_timeout_ms: 1_000,
|
||||
request_deadline: None,
|
||||
};
|
||||
let error = PlatformImageError::InvalidRequest {
|
||||
provider: VECTOR_ENGINE_PROVIDER,
|
||||
message: "model unavailable".to_string(),
|
||||
};
|
||||
assert!(!should_fallback_to_gpt_image_2_c(
|
||||
GPT_IMAGE_2_MODEL,
|
||||
GPT_IMAGE_2_MODEL,
|
||||
1,
|
||||
&error,
|
||||
&settings,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn image_provider_send_retry_delay_uses_exponential_backoff_with_bounded_jitter() {
|
||||
assert_eq!(image_provider_send_retry_delay_ms(1, 0), 500);
|
||||
|
||||
Reference in New Issue
Block a user