删除抠图上海自有 OSS 死分支并清理审查发现的死代码

代码审查发现 4 项问题,本次一并处理:

- 抠图输入"上海地域自有 OSS 上传"分支整体删除:我们没有上海地域
  OSS,region marker 判定永远为假,该分支任何环境都不会触发,且其
  matting-input/ 中间对象无清理会造成存储泄漏(若将来启用)。抠图
  输入统一走 VIAPI 官方临时桶(1 天自动过期,天然无泄漏)。
- platform-matting:segment_image_to_transparent_png 去掉恒为 None
  的 accessible_url 参数,简化提交分支;修正"生产建议用上海自有
  OSS"的误导注释。
- editor_green_screen:删除不可达的 #00FF00 绿幕特判分支(legacy
  绿幕色产生点已删、调色板无此色)。
- segment_smoke example:默认参数里的个人路径改为用法提示 + 退出。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 04:32:11 +00:00
parent b8c2efaf24
commit a2b64290a1
4 changed files with 15 additions and 102 deletions
@@ -1,24 +1,15 @@
//! 阿里云通用抠图在 api-server 侧的适配层。
//!
//! 输入 URL 策略:自有 OSS 在上海地域时直接上传草稿区并签名读 URL(抠图服务只认
//! 上海地域 OSS);其他地域交给 platform-matting VIAPI 官方临时桶。
use std::collections::BTreeMap;
//! 输入 URL 策略:抠图服务只认上海地域 OSS URL,而我们没有上海地域自有 OSS,
//! 统一由 platform-matting 上传 VIAPI 官方临时桶1 天自动过期,无需清理)
use axum::http::StatusCode;
use platform_oss::{
LegacyAssetPrefix, OssObjectAccess, OssPutObjectRequest, OssSignedGetObjectUrlRequest,
};
use serde_json::json;
use crate::{
http_error::AppError, openai_image_generation::DownloadedOpenAiImage, state::AppState,
};
const MATTING_INPUT_PATH_SEGMENT: &str = "matting-input";
const MATTING_INPUT_READ_EXPIRE_SECONDS: u64 = 10 * 60;
const ALIYUN_MATTING_OSS_REGION_MARKER: &str = "oss-cn-shanghai";
/// 图片字节 → 阿里云通用抠图 → 原尺寸透明 PNG。
/// 未配置抠图客户端时返回错误,由调用方决定是否降级本地算法。
pub(crate) async fn segment_image_with_aliyun_matting(
@@ -33,11 +24,10 @@ pub(crate) async fn segment_image_with_aliyun_matting(
}))
})?;
let accessible_url = prepare_shanghai_oss_input_url(state, image, log_label).await;
let file_name = format!("{log_label}.png");
let started_at = std::time::Instant::now();
let output_bytes = matting_client
.segment_image_to_transparent_png(image.bytes.as_slice(), &file_name, accessible_url)
.segment_image_to_transparent_png(image.bytes.as_slice(), &file_name)
.await
.map_err(|error| {
AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
@@ -58,67 +48,3 @@ pub(crate) async fn segment_image_with_aliyun_matting(
extension: "png".to_string(),
})
}
/// 自有 OSS 在上海地域时,把待抠图图片传到草稿区并返回签名读 URL;
/// 其他情况返回 Noneplatform-matting 会转走官方临时桶)。
/// 该步骤失败不阻断抠图,只是退化为临时桶通道。
async fn prepare_shanghai_oss_input_url(
state: &AppState,
image: &DownloadedOpenAiImage,
log_label: &str,
) -> Option<String> {
let oss_client = state.oss_client()?;
let endpoint = state.config.oss_endpoint.as_deref().unwrap_or("");
if !endpoint.contains(ALIYUN_MATTING_OSS_REGION_MARKER) {
return None;
}
let http_client = reqwest::Client::new();
let file_name = format!(
"{log_label}-{}.{}",
shared_kernel::new_uuid_simple_string(),
image.extension
);
let put_result = oss_client
.put_object(
&http_client,
OssPutObjectRequest {
prefix: LegacyAssetPrefix::CharacterDrafts,
path_segments: vec![MATTING_INPUT_PATH_SEGMENT.to_string()],
file_name,
content_type: Some(image.mime_type.clone()),
access: OssObjectAccess::Private,
metadata: BTreeMap::new(),
body: image.bytes.clone(),
},
)
.await;
let put_result = match put_result {
Ok(result) => result,
Err(error) => {
tracing::warn!(
provider = "aliyun-matting",
log_label,
error = %error,
"抠图输入图上传自有 OSS 失败,回退官方临时桶"
);
return None;
}
};
match oss_client.sign_get_object_url(OssSignedGetObjectUrlRequest {
object_key: put_result.object_key,
expire_seconds: Some(MATTING_INPUT_READ_EXPIRE_SECONDS),
}) {
Ok(signed) => Some(signed.signed_url),
Err(error) => {
tracing::warn!(
provider = "aliyun-matting",
log_label,
error = %error,
"抠图输入图签名读 URL 失败,回退官方临时桶"
);
None
}
}
}
@@ -141,9 +141,6 @@ pub(crate) const EDITOR_GREEN_SCREEN_CHARACTER_GUARDRAILS: &str =
"角色主体及其服饰、道具的颜色必须与背景色明显区分,不得带与背景色相同或相近的描边、投影或反光";
fn editor_screen_background_color_prompt(color: EditorScreenBackgroundColor) -> String {
if color.hex == "#00FF00" {
return "单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕".to_string();
}
format!(
"单一纯色背景 {} {} / RGB({},{},{})",
color.label, color.hex, color.red, color.green, color.blue
@@ -33,7 +33,8 @@ async fn main() {
load_env_files();
let input_path = std::env::args().nth(1).unwrap_or_else(|| {
r"C:\Users\lingh\Downloads\gpt-image-2-elf-archer-2048x2048.png".to_string()
eprintln!("用法:cargo run -p platform-matting --example segment_smoke -- <图片路径>");
std::process::exit(1);
});
let input_bytes = std::fs::read(&input_path)
.unwrap_or_else(|error| panic!("读取测试图片失败({input_path}):{error}"));
+10 -21
View File
@@ -18,8 +18,8 @@ pub const DEFAULT_IMAGESEG_ENDPOINT: &str = "imageseg.cn-shanghai.aliyuncs.com";
const IMAGESEG_API_VERSION: &str = "2019-12-30";
const SEGMENT_COMMON_IMAGE_ACTION: &str = "SegmentCommonImage";
// VIAPI 官方临时上传通道:非上海地域 OSS / 本地文件先传官方临时桶(1 天过期,
// 全用户共享 QPS,生产建议直接用上海地域自有 OSS
// VIAPI 官方临时上传通道:抠图输入统一先传官方临时桶(1 天自动过期,无需清理;
// 全用户共享 QPS)。抠图服务只认上海地域 OSS URL,而我们没有上海地域自有 OSS。
// 文档:https://help.aliyun.com/document_detail/155645.html
const VIAPI_UTILS_ENDPOINT: &str = "viapiutils.cn-shanghai.aliyuncs.com";
const VIAPI_UTILS_VERSION: &str = "2020-04-01";
@@ -282,15 +282,13 @@ impl MattingClient {
/// 图片字节 → 通用抠图 → 原尺寸透明 PNG 字节。
///
/// - `accessible_url`:该字节对应的、抠图服务可访问的 URL(上海地域 OSS 签名 URL
/// 为 None 或图片超分辨率上限需要缩图时,自动改走官方临时桶上传。
/// - 输入统一上传 VIAPI 官方临时桶(1 天自动过期,无需清理)后作为 ImageURL 送抠
/// - 分辨率守卫:任一边 >= 2000 时先等比缩小送抠,抠完只取结果 alpha 上采样回贴
/// 原图 RGB,保证输出与输入同尺寸、画质无损。
pub async fn segment_image_to_transparent_png(
&self,
bytes: &[u8],
file_name: &str,
accessible_url: Option<String>,
) -> Result<Vec<u8>, MattingError> {
let source = image::load_from_memory(bytes).map_err(|error| {
MattingError::InvalidRequest(format!("解析待抠图图片失败:{error}"))
@@ -299,28 +297,19 @@ impl MattingClient {
let (source_width, source_height) = source_rgba.dimensions();
let needs_resize = source_width > MAX_INPUT_EDGE || source_height > MAX_INPUT_EDGE;
let (submit_bytes, submit_url) = if needs_resize {
let upload_bytes = if needs_resize {
let resized = source.resize(
MAX_INPUT_EDGE,
MAX_INPUT_EDGE,
image::imageops::FilterType::CatmullRom,
);
let resized_bytes = encode_rgba_png(&resized.to_rgba8())?;
(Some(resized_bytes), None)
encode_rgba_png(&resized.to_rgba8())?
} else {
(None, accessible_url)
};
let image_url = match submit_url {
Some(url) => url,
None => {
let upload_bytes = submit_bytes
.clone()
.unwrap_or_else(|| bytes.to_vec());
self.upload_temp_image(upload_bytes, file_name, "image/png")
.await?
}
bytes.to_vec()
};
let image_url = self
.upload_temp_image(upload_bytes, file_name, "image/png")
.await?;
let result = self
.segment_common_image(SegmentCommonImageRequest {
@@ -385,7 +374,7 @@ impl MattingClient {
}
/// 把本地图片字节上传到 VIAPI 官方临时桶,返回可直接作为 ImageURL 的公网地址。
/// 适用于本地文件或非上海地域 OSS 的开发/调试场景;生产建议用上海地域自有 OSS
/// 抠图输入的统一上传通道(我们没有上海地域自有 OSS,临时桶 1 天自动过期无需清理)
pub async fn upload_temp_image(
&self,
bytes: Vec<u8>,