切换阿里云通用抠图正式上传链路

改用 AuthorizeFileUpload 与 Policy POST 上传临时对象

移除 GetOssStsToken、OSS V1 和 SHA-1 依赖

补充真实链路冒烟示例、单元测试与架构运维文档
This commit is contained in:
2026-07-15 05:22:34 +00:00
parent 2f092c3566
commit c6aa8a248a
8 changed files with 291 additions and 173 deletions
-3
View File
@@ -4481,18 +4481,15 @@ dependencies = [
name = "platform-matting"
version = "0.1.0"
dependencies = [
"base64 0.22.1",
"dotenvy",
"hex",
"hmac",
"httpdate",
"image",
"platform-oss",
"reqwest 0.12.28",
"serde",
"serde_json",
"serde_urlencoded",
"sha1",
"sha2",
"time",
"tokio",
@@ -1,7 +1,6 @@
//! 阿里云通用抠图在 api-server 侧的适配层。
//!
//! 输入 URL 策略:抠图服务只认上海地域 OSS URL,而我们没有上海地域自有 OSS,
//! 统一由 platform-matting 上传 VIAPI 官方临时桶(1 天自动过期,无需清理)。
//! 输入统一由 platform-matting 通过 AuthorizeFileUpload 单对象 Policy 上传动态临时 OSS。
use axum::http::StatusCode;
use platform_matting::MattingError;
@@ -108,7 +107,7 @@ mod tests {
),
MattingError::InvalidRequest("解析待抠图图片失败:invalid png".to_string()),
MattingError::InvalidConfig("endpoint 为空".to_string()),
MattingError::Sign("初始化 OSS V1 签名器失败".to_string()),
MattingError::Sign("构造 AuthorizeFileUpload 签名失败".to_string()),
] {
let mapped = aliyun_matting_failure_to_app_error(&error, 3);
+1 -4
View File
@@ -5,13 +5,10 @@ version.workspace = true
license.workspace = true
[dependencies]
base64 = { workspace = true }
hmac = { workspace = true }
hex = { workspace = true }
httpdate = { workspace = true }
image = { workspace = true, features = ["png", "jpeg", "webp"] }
sha1 = { workspace = true }
reqwest = { workspace = true, features = ["json", "rustls-tls"] }
reqwest = { workspace = true, features = ["json", "multipart", "rustls-tls"] }
serde = { workspace = true }
serde_json = { workspace = true }
serde_urlencoded = { workspace = true }
@@ -1,4 +1,4 @@
//! 通用抠图冒烟验证:本地图片 → OSS → SegmentCommonImage → 下载结果。
//! 通用抠图冒烟验证:本地图片 → AuthorizeFileUpload 临时对象 → SegmentCommonImage → 下载结果。
//!
//! 运行(在 server-rs 目录下):
//! cargo run -p platform-matting --example segment_smoke -- "C:\path\to\input.png"
@@ -38,17 +38,16 @@ async fn main() {
});
let input_bytes = std::fs::read(&input_path)
.unwrap_or_else(|error| panic!("读取测试图片失败({input_path}):{error}"));
println!("[1/5] 已读取测试图片:{input_path}({} 字节)", input_bytes.len());
println!(
"[1/5] 已读取测试图片:{input_path}({} 字节)",
input_bytes.len()
);
// SegmentCommonImage 要求分辨率低于 2000x2000,超限先等比缩小。
const MAX_EDGE: u32 = 1999;
let decoded = image::load_from_memory(&input_bytes).expect("测试图片应可解码");
let input_bytes = if decoded.width() > MAX_EDGE || decoded.height() > MAX_EDGE {
let resized = decoded.resize(
MAX_EDGE,
MAX_EDGE,
image::imageops::FilterType::CatmullRom,
);
let resized = decoded.resize(MAX_EDGE, MAX_EDGE, image::imageops::FilterType::CatmullRom);
let mut buffer = std::io::Cursor::new(Vec::new());
resized
.write_to(&mut buffer, image::ImageFormat::Png)
@@ -68,11 +67,16 @@ async fn main() {
let http_client = reqwest::Client::new();
// --- 调用通用抠图 ---
// key 优先级:VIAPI 专用 → 官方 SDK 标准命名(#IMAGE_CALL)→ 短信 key 兜底。
// key 优先级与 api-server 配置保持一致:抠图专用 → 官方 SDK 标准命名。
let (matting_key_id, matting_key_secret) = [
("ALIYUN_IMAGESEG_ACCESS_KEY_ID", "ALIYUN_IMAGESEG_ACCESS_KEY_SECRET"),
("ALIBABA_CLOUD_ACCESS_KEY_ID", "ALIBABA_CLOUD_ACCESS_KEY_SECRET"),
("ALIYUN_SMS_ACCESS_KEY_ID", "ALIYUN_SMS_ACCESS_KEY_SECRET"),
(
"GENARRATIVE_ALIYUN_MATTING_ACCESS_KEY_ID",
"GENARRATIVE_ALIYUN_MATTING_ACCESS_KEY_SECRET",
),
(
"ALIBABA_CLOUD_ACCESS_KEY_ID",
"ALIBABA_CLOUD_ACCESS_KEY_SECRET",
),
]
.iter()
.find_map(|(id_name, secret_name)| {
@@ -86,7 +90,7 @@ async fn main() {
})
.expect("未找到可用的抠图 AccessKey 环境变量");
let matting_config = MattingConfig::new(
std::env::var("ALIYUN_IMAGESEG_ENDPOINT")
std::env::var("GENARRATIVE_ALIYUN_MATTING_ENDPOINT")
.unwrap_or_else(|_| DEFAULT_IMAGESEG_ENDPOINT.to_string()),
matting_key_id,
matting_key_secret,
@@ -94,12 +98,12 @@ async fn main() {
.expect("抠图配置应有效");
let matting_client = MattingClient::new(matting_config).expect("抠图客户端应可构建");
// 本地 OSS 在北京地域,抠图服务要求上海地域,走 VIAPI 官方临时桶上传。
// 非上海地域输入按新版官方 SDK 的 AdvanceRequest 口径申请单对象 Policy 后上传。
let temp_url = matting_client
.upload_temp_image(input_bytes, "segment-input.png", "image/png")
.await
.expect("上传 VIAPI 临时桶应成功");
println!("[2/5] 已上传 VIAPI 临时桶");
.expect("上传 AuthorizeFileUpload 临时对象应成功");
println!("[2/5] 已上传 AuthorizeFileUpload 临时对象");
println!("[3/5] 输入图 URL host:{}", host_of(&temp_url));
let result = matting_client
File diff suppressed because it is too large Load Diff