provider按参数分层并公开组合校验入口
- submit 改为接收生成参数,图片输入由调用方解析后单独传入 - 公开 validate_text_to_model_params / validate_image_to_model_params 供平台层在副作用前预检 - 参数到 provider 校验选项的映射收敛为 From 实现,去掉重复拼装 - smoke 示例跟随新签名
This commit is contained in:
@@ -17,9 +17,9 @@ use std::{env, time::Duration};
|
||||
use platform_tripo::TripoProviderClient;
|
||||
use shared_contracts::model3d::{
|
||||
common::{Model3dModelVersion, Model3dTaskStatus, Model3dTextureQuality},
|
||||
image_to_model::Model3dImageToModelRequest,
|
||||
image_to_model::Model3dImageToModelParams,
|
||||
multiview_to_model::{Model3dMultiviewInputs, Model3dMultiviewToModelRequest},
|
||||
text_to_model::Model3dTextToModelRequest,
|
||||
text_to_model::Model3dTextToModelParams,
|
||||
};
|
||||
use tokio::{fs::File, io::AsyncWriteExt};
|
||||
use tripo3d_sdk::{ClientOptions, TripoClient, WaitOptions};
|
||||
@@ -46,7 +46,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
))?;
|
||||
|
||||
let text = client
|
||||
.submit(&Model3dTextToModelRequest {
|
||||
.submit(&Model3dTextToModelParams {
|
||||
prompt: "a low-poly wooden treasure chest".to_string(),
|
||||
model: Model3dModelVersion::H31,
|
||||
negative_prompt: None,
|
||||
@@ -72,29 +72,31 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("text_to_model task_id={}", text.task_id);
|
||||
|
||||
let image = client
|
||||
.submit_image_to_model(&Model3dImageToModelRequest {
|
||||
input: SAMPLE_IMAGE_URL.to_string(),
|
||||
model: Model3dModelVersion::H31,
|
||||
enable_image_autofix: None,
|
||||
model_seed: None,
|
||||
texture_seed: None,
|
||||
texture: Some(true),
|
||||
pbr: Some(true),
|
||||
texture_quality: Some(Model3dTextureQuality::Standard),
|
||||
texture_version: None,
|
||||
delight: None,
|
||||
texture_alignment: None,
|
||||
geometry_quality: None,
|
||||
face_limit: None,
|
||||
auto_size: None,
|
||||
orientation: None,
|
||||
quad: None,
|
||||
smart_low_poly: None,
|
||||
generate_parts: None,
|
||||
compress: None,
|
||||
export_uv: None,
|
||||
export_orientation: None,
|
||||
})
|
||||
.submit_image_to_model(
|
||||
SAMPLE_IMAGE_URL,
|
||||
&Model3dImageToModelParams {
|
||||
model: Model3dModelVersion::H31,
|
||||
enable_image_autofix: None,
|
||||
model_seed: None,
|
||||
texture_seed: None,
|
||||
texture: Some(true),
|
||||
pbr: Some(true),
|
||||
texture_quality: Some(Model3dTextureQuality::Standard),
|
||||
texture_version: None,
|
||||
delight: None,
|
||||
texture_alignment: None,
|
||||
geometry_quality: None,
|
||||
face_limit: None,
|
||||
auto_size: None,
|
||||
orientation: None,
|
||||
quad: None,
|
||||
smart_low_poly: None,
|
||||
generate_parts: None,
|
||||
compress: None,
|
||||
export_uv: None,
|
||||
export_orientation: None,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
println!("image_to_model task_id={}", image.task_id);
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ use shared_contracts::model3d::common::{
|
||||
Model3dCompression, Model3dGeometryQuality, Model3dModelVersion, Model3dTextureQuality,
|
||||
Model3dTextureVersion,
|
||||
};
|
||||
use shared_contracts::model3d::image_to_model::Model3dImageToModelParams;
|
||||
use shared_contracts::model3d::text_to_model::Model3dTextToModelParams;
|
||||
|
||||
use super::{TripoError, TripoField, TripoValidationReason};
|
||||
|
||||
@@ -20,6 +22,44 @@ pub(crate) struct TripoGenerationOptions {
|
||||
pub compress: Option<Model3dCompression>,
|
||||
}
|
||||
|
||||
impl From<&Model3dTextToModelParams> for TripoGenerationOptions {
|
||||
fn from(params: &Model3dTextToModelParams) -> Self {
|
||||
Self {
|
||||
model: params.model,
|
||||
texture: params.texture,
|
||||
pbr: params.pbr,
|
||||
texture_quality: params.texture_quality,
|
||||
texture_version: params.texture_version,
|
||||
geometry_quality: params.geometry_quality,
|
||||
face_limit: params.face_limit,
|
||||
auto_size: params.auto_size,
|
||||
quad: params.quad,
|
||||
smart_low_poly: params.smart_low_poly,
|
||||
generate_parts: params.generate_parts,
|
||||
compress: params.compress,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Model3dImageToModelParams> for TripoGenerationOptions {
|
||||
fn from(params: &Model3dImageToModelParams) -> Self {
|
||||
Self {
|
||||
model: params.model,
|
||||
texture: params.texture,
|
||||
pbr: params.pbr,
|
||||
texture_quality: params.texture_quality,
|
||||
texture_version: params.texture_version,
|
||||
geometry_quality: params.geometry_quality,
|
||||
face_limit: params.face_limit,
|
||||
auto_size: params.auto_size,
|
||||
quad: params.quad,
|
||||
smart_low_poly: params.smart_low_poly,
|
||||
generate_parts: params.generate_parts,
|
||||
compress: params.compress,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn validate_generation_options(
|
||||
options: &TripoGenerationOptions,
|
||||
) -> Result<(), TripoError> {
|
||||
|
||||
@@ -2,87 +2,79 @@ use shared_contracts::model3d::common::{
|
||||
Model3dCompression, Model3dExportOrientation, Model3dGeometryQuality, Model3dInputOrientation,
|
||||
Model3dTextureAlignment, Model3dTextureQuality, Model3dTextureVersion,
|
||||
};
|
||||
use shared_contracts::model3d::image_to_model::Model3dImageToModelRequest;
|
||||
use shared_contracts::model3d::image_to_model::Model3dImageToModelParams;
|
||||
use tripo3d_sdk::{models::FileInput, params::ImageToModelParams};
|
||||
|
||||
use crate::common::{
|
||||
TripoError, TripoField, TripoGenerationOptions, TripoProviderClient, TripoTaskHandle,
|
||||
TripoValidationReason, validate_generation_options,
|
||||
TripoError, TripoField, TripoProviderClient, TripoTaskHandle, TripoValidationReason,
|
||||
};
|
||||
|
||||
use super::validation::validate_image_to_model_params;
|
||||
|
||||
impl TripoProviderClient {
|
||||
/// 图片输入由调用方解析后传入:provider 只负责把它交给 SDK,
|
||||
/// 站内资源 / 素材的归属校验属于平台层。
|
||||
pub async fn submit_image_to_model(
|
||||
&self,
|
||||
request: &Model3dImageToModelRequest,
|
||||
input: &str,
|
||||
params: &Model3dImageToModelParams,
|
||||
) -> Result<TripoTaskHandle, TripoError> {
|
||||
if request.input.trim().is_empty() {
|
||||
let input = input.trim();
|
||||
if input.is_empty() {
|
||||
return Err(TripoError::InvalidParameters {
|
||||
field: Some(TripoField::Input),
|
||||
reason: TripoValidationReason::Required,
|
||||
message: "input must not be blank".into(),
|
||||
});
|
||||
}
|
||||
validate_generation_options(&TripoGenerationOptions {
|
||||
model: request.model,
|
||||
texture: request.texture,
|
||||
pbr: request.pbr,
|
||||
texture_quality: request.texture_quality,
|
||||
texture_version: request.texture_version,
|
||||
geometry_quality: request.geometry_quality,
|
||||
face_limit: request.face_limit,
|
||||
auto_size: request.auto_size,
|
||||
quad: request.quad,
|
||||
smart_low_poly: request.smart_low_poly,
|
||||
generate_parts: request.generate_parts,
|
||||
compress: request.compress,
|
||||
})?;
|
||||
validate_image_to_model_params(params)?;
|
||||
|
||||
let task_id = self
|
||||
.client
|
||||
.image_to_model(to_sdk_params(request))
|
||||
.image_to_model(to_sdk_params(input, params))
|
||||
.await
|
||||
.map_err(TripoError::from)?;
|
||||
Ok(TripoTaskHandle { task_id })
|
||||
}
|
||||
}
|
||||
|
||||
fn to_sdk_params(request: &Model3dImageToModelRequest) -> ImageToModelParams {
|
||||
fn to_sdk_params(input: &str, params: &Model3dImageToModelParams) -> ImageToModelParams {
|
||||
ImageToModelParams {
|
||||
input: FileInput::from(request.input.trim()),
|
||||
model: Some(request.model.as_str().to_owned()),
|
||||
enable_image_autofix: request.enable_image_autofix,
|
||||
model_seed: request.model_seed,
|
||||
texture_seed: request.texture_seed,
|
||||
texture: request.texture,
|
||||
pbr: request.pbr,
|
||||
texture_quality: request
|
||||
input: FileInput::from(input),
|
||||
model: Some(params.model.as_str().to_owned()),
|
||||
enable_image_autofix: params.enable_image_autofix,
|
||||
model_seed: params.model_seed,
|
||||
texture_seed: params.texture_seed,
|
||||
texture: params.texture,
|
||||
pbr: params.pbr,
|
||||
texture_quality: params
|
||||
.texture_quality
|
||||
.map(Model3dTextureQuality::as_str)
|
||||
.map(str::to_owned),
|
||||
extra: extra_fields(request.texture_version, request.delight),
|
||||
texture_alignment: request
|
||||
extra: extra_fields(params.texture_version, params.delight),
|
||||
texture_alignment: params
|
||||
.texture_alignment
|
||||
.map(Model3dTextureAlignment::as_str)
|
||||
.map(str::to_owned),
|
||||
geometry_quality: request
|
||||
geometry_quality: params
|
||||
.geometry_quality
|
||||
.map(Model3dGeometryQuality::as_str)
|
||||
.map(str::to_owned),
|
||||
face_limit: request.face_limit,
|
||||
auto_size: request.auto_size,
|
||||
orientation: request
|
||||
face_limit: params.face_limit,
|
||||
auto_size: params.auto_size,
|
||||
orientation: params
|
||||
.orientation
|
||||
.map(Model3dInputOrientation::as_str)
|
||||
.map(str::to_owned),
|
||||
quad: request.quad,
|
||||
smart_low_poly: request.smart_low_poly,
|
||||
generate_parts: request.generate_parts,
|
||||
compress: request
|
||||
quad: params.quad,
|
||||
smart_low_poly: params.smart_low_poly,
|
||||
generate_parts: params.generate_parts,
|
||||
compress: params
|
||||
.compress
|
||||
.map(Model3dCompression::as_str)
|
||||
.map(str::to_owned),
|
||||
export_uv: request.export_uv,
|
||||
export_orientation: request
|
||||
export_uv: params.export_uv,
|
||||
export_orientation: params
|
||||
.export_orientation
|
||||
.map(Model3dExportOrientation::as_str)
|
||||
.map(str::to_owned),
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
mod client;
|
||||
pub mod result;
|
||||
mod validation;
|
||||
|
||||
pub use validation::validate_image_to_model_params;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
use shared_contracts::model3d::image_to_model::Model3dImageToModelParams;
|
||||
|
||||
use crate::common::{TripoError, validate_generation_options};
|
||||
|
||||
/// image-to-model 的请求预检:只覆盖生成参数与模型能力组合,
|
||||
/// 图片本体是否可解析由调用方保证(provider 在 submit 时仍会拒绝空输入)。
|
||||
pub fn validate_image_to_model_params(
|
||||
params: &Model3dImageToModelParams,
|
||||
) -> Result<(), TripoError> {
|
||||
validate_generation_options(¶ms.into())
|
||||
}
|
||||
@@ -13,3 +13,5 @@ pub use common::{
|
||||
TripoTaskFailure, TripoTaskHandle, TripoTaskOutput, TripoTaskSnapshot, TripoTaskType, TripoUrl,
|
||||
TripoValidationReason,
|
||||
};
|
||||
pub use image_to_model::validate_image_to_model_params;
|
||||
pub use text_to_model::validate_text_to_model_params;
|
||||
|
||||
@@ -3,55 +3,55 @@ use shared_contracts::model3d::common::{
|
||||
Model3dCompression, Model3dExportOrientation, Model3dGeometryQuality, Model3dTextureQuality,
|
||||
Model3dTextureVersion,
|
||||
};
|
||||
use shared_contracts::model3d::text_to_model::Model3dTextToModelRequest;
|
||||
use shared_contracts::model3d::text_to_model::Model3dTextToModelParams;
|
||||
|
||||
use super::validation::validate_text_to_model_request;
|
||||
use super::validation::validate_text_to_model_params;
|
||||
|
||||
impl TripoProviderClient {
|
||||
pub async fn submit(
|
||||
&self,
|
||||
request: &Model3dTextToModelRequest,
|
||||
params: &Model3dTextToModelParams,
|
||||
) -> Result<TripoTaskHandle, TripoError> {
|
||||
validate_text_to_model_request(request)?;
|
||||
validate_text_to_model_params(params)?;
|
||||
let task_id = self
|
||||
.client
|
||||
.text_to_model(to_sdk_params(request))
|
||||
.text_to_model(to_sdk_params(params))
|
||||
.await
|
||||
.map_err(TripoError::from)?;
|
||||
Ok(TripoTaskHandle { task_id })
|
||||
}
|
||||
}
|
||||
|
||||
fn to_sdk_params(request: &Model3dTextToModelRequest) -> tripo3d_sdk::params::TextToModelParams {
|
||||
fn to_sdk_params(params: &Model3dTextToModelParams) -> tripo3d_sdk::params::TextToModelParams {
|
||||
tripo3d_sdk::params::TextToModelParams {
|
||||
prompt: request.prompt.clone(),
|
||||
model: Some(request.model.as_str().to_owned()),
|
||||
negative_prompt: request.negative_prompt.clone(),
|
||||
image_seed: request.image_seed,
|
||||
model_seed: request.model_seed,
|
||||
texture_seed: request.texture_seed,
|
||||
texture: request.texture,
|
||||
pbr: request.pbr,
|
||||
texture_quality: request
|
||||
prompt: params.prompt.clone(),
|
||||
model: Some(params.model.as_str().to_owned()),
|
||||
negative_prompt: params.negative_prompt.clone(),
|
||||
image_seed: params.image_seed,
|
||||
model_seed: params.model_seed,
|
||||
texture_seed: params.texture_seed,
|
||||
texture: params.texture,
|
||||
pbr: params.pbr,
|
||||
texture_quality: params
|
||||
.texture_quality
|
||||
.map(Model3dTextureQuality::as_str)
|
||||
.map(str::to_owned),
|
||||
extra: extra_fields(request.texture_version, request.delight),
|
||||
geometry_quality: request
|
||||
extra: extra_fields(params.texture_version, params.delight),
|
||||
geometry_quality: params
|
||||
.geometry_quality
|
||||
.map(Model3dGeometryQuality::as_str)
|
||||
.map(str::to_owned),
|
||||
face_limit: request.face_limit,
|
||||
auto_size: request.auto_size,
|
||||
quad: request.quad,
|
||||
smart_low_poly: request.smart_low_poly,
|
||||
generate_parts: request.generate_parts,
|
||||
compress: request
|
||||
face_limit: params.face_limit,
|
||||
auto_size: params.auto_size,
|
||||
quad: params.quad,
|
||||
smart_low_poly: params.smart_low_poly,
|
||||
generate_parts: params.generate_parts,
|
||||
compress: params
|
||||
.compress
|
||||
.map(Model3dCompression::as_str)
|
||||
.map(str::to_owned),
|
||||
export_uv: request.export_uv,
|
||||
export_orientation: request
|
||||
export_uv: params.export_uv,
|
||||
export_orientation: params
|
||||
.export_orientation
|
||||
.map(Model3dExportOrientation::as_str)
|
||||
.map(str::to_owned),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
mod client;
|
||||
pub mod result;
|
||||
mod validation;
|
||||
|
||||
pub use validation::validate_text_to_model_params;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
use shared_contracts::model3d::text_to_model::Model3dTextToModelRequest;
|
||||
use shared_contracts::model3d::text_to_model::Model3dTextToModelParams;
|
||||
|
||||
use crate::common::{
|
||||
TripoError, TripoField, TripoGenerationOptions, TripoValidationReason,
|
||||
validate_generation_options,
|
||||
};
|
||||
use crate::common::{TripoError, TripoField, TripoValidationReason, validate_generation_options};
|
||||
|
||||
pub(crate) fn validate_text_to_model_request(
|
||||
request: &Model3dTextToModelRequest,
|
||||
) -> Result<(), TripoError> {
|
||||
if request.prompt.trim().is_empty() {
|
||||
/// text-to-model 的请求预检:调用方在产生 provider 副作用之前调用,
|
||||
/// 用于把参数错误映射成调用方的入参错误,而不是等 submit 失败。
|
||||
pub fn validate_text_to_model_params(params: &Model3dTextToModelParams) -> Result<(), TripoError> {
|
||||
if params.prompt.trim().is_empty() {
|
||||
return Err(TripoError::InvalidParameters {
|
||||
field: Some(TripoField::Prompt),
|
||||
reason: TripoValidationReason::Required,
|
||||
@@ -16,14 +13,14 @@ pub(crate) fn validate_text_to_model_request(
|
||||
});
|
||||
}
|
||||
|
||||
if request.prompt.chars().count() > 1024 {
|
||||
if params.prompt.chars().count() > 1024 {
|
||||
return Err(TripoError::InvalidParameters {
|
||||
field: Some(TripoField::Prompt),
|
||||
reason: TripoValidationReason::InvalidCombination,
|
||||
message: "prompt must not exceed 1024 characters".into(),
|
||||
});
|
||||
}
|
||||
if request
|
||||
if params
|
||||
.negative_prompt
|
||||
.as_deref()
|
||||
.is_some_and(|value| value.chars().count() > 255)
|
||||
@@ -35,20 +32,7 @@ pub(crate) fn validate_text_to_model_request(
|
||||
});
|
||||
}
|
||||
|
||||
validate_generation_options(&TripoGenerationOptions {
|
||||
model: request.model,
|
||||
texture: request.texture,
|
||||
pbr: request.pbr,
|
||||
texture_quality: request.texture_quality,
|
||||
texture_version: request.texture_version,
|
||||
geometry_quality: request.geometry_quality,
|
||||
face_limit: request.face_limit,
|
||||
auto_size: request.auto_size,
|
||||
quad: request.quad,
|
||||
smart_low_poly: request.smart_low_poly,
|
||||
generate_parts: request.generate_parts,
|
||||
compress: request.compress,
|
||||
})?;
|
||||
validate_generation_options(¶ms.into())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user