按接口收紧Tripo任务结果类型
为 text、image、multiview 三类生成定义独立必填结果结构 以枚举关联任务类型与具体结果并对缺失字段失败关闭 将通用 URL 类型由 TripoModelUrl 更名为 TripoUrl
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
use tripo3d_sdk::TripoClient;
|
||||
|
||||
use super::{
|
||||
TripoDownloadedModel, TripoError, TripoModelUrl, TripoSettings, TripoTaskHandle,
|
||||
TripoTaskSnapshot, map_task, validate_task_id,
|
||||
TripoDownloadedModel, TripoError, TripoSettings, TripoTaskHandle, TripoTaskSnapshot, TripoUrl,
|
||||
map_task, validate_task_id,
|
||||
};
|
||||
|
||||
pub struct TripoProviderClient {
|
||||
@@ -49,7 +49,7 @@ impl TripoProviderClient {
|
||||
task_id: handle.task_id.clone(),
|
||||
message: "completed task has no model URL".into(),
|
||||
})?;
|
||||
let url = TripoModelUrl::parse(&downloaded.url).map_err(|error| match error {
|
||||
let url = TripoUrl::parse(&downloaded.url).map_err(|error| match error {
|
||||
TripoError::OutputSchema { message, .. } => TripoError::OutputSchema {
|
||||
task_id: handle.task_id.clone(),
|
||||
message,
|
||||
|
||||
@@ -2,8 +2,13 @@ use shared_contracts::model3d::common::Model3dTaskStatus;
|
||||
use tripo3d_sdk::{Task, TaskOutput, TaskStatus};
|
||||
|
||||
use super::{
|
||||
TripoError, TripoModelUrl, TripoTaskFailure, TripoTaskHandle, TripoTaskOutput,
|
||||
TripoTaskSnapshot, TripoTaskType,
|
||||
TripoError, TripoTaskFailure, TripoTaskHandle, TripoTaskOutput, TripoTaskSnapshot,
|
||||
TripoTaskType, TripoUrl,
|
||||
};
|
||||
use crate::{
|
||||
image_to_model::result::TripoImageToModelResult,
|
||||
multiview_to_model::result::TripoMultiviewToModelResult,
|
||||
text_to_model::result::TripoTextToModelResult,
|
||||
};
|
||||
|
||||
pub(crate) fn map_task(task: Task) -> Result<TripoTaskSnapshot, TripoError> {
|
||||
@@ -13,6 +18,7 @@ pub(crate) fn map_task(task: Task) -> Result<TripoTaskSnapshot, TripoError> {
|
||||
let output = match status {
|
||||
Model3dTaskStatus::Completed => Some(map_output(
|
||||
&task_id,
|
||||
&task_type,
|
||||
task.output
|
||||
.as_ref()
|
||||
.ok_or_else(|| TripoError::OutputSchema {
|
||||
@@ -66,52 +72,51 @@ fn map_status(status: TaskStatus) -> Result<Model3dTaskStatus, TripoError> {
|
||||
}
|
||||
}
|
||||
|
||||
fn map_output(task_id: &str, output: &TaskOutput) -> Result<TripoTaskOutput, TripoError> {
|
||||
let mut model_urls = Vec::new();
|
||||
for candidate in output
|
||||
.model_urls
|
||||
.iter()
|
||||
.flat_map(|urls| urls.iter())
|
||||
.chain(output.model_url.iter())
|
||||
.chain(output.model.iter())
|
||||
.chain(output.pbr_model.iter())
|
||||
.chain(output.base_model.iter())
|
||||
{
|
||||
if !model_urls
|
||||
.iter()
|
||||
.any(|url: &TripoModelUrl| url.as_str() == candidate)
|
||||
{
|
||||
model_urls.push(parse_url(candidate, task_id)?);
|
||||
}
|
||||
}
|
||||
if model_urls.is_empty() {
|
||||
return Err(TripoError::OutputSchema {
|
||||
task_id: task_id.into(),
|
||||
message: "completed task output contains no model URL".into(),
|
||||
});
|
||||
}
|
||||
fn map_output(
|
||||
task_id: &str,
|
||||
task_type: &TripoTaskType,
|
||||
output: &TaskOutput,
|
||||
) -> Result<TripoTaskOutput, TripoError> {
|
||||
let model_url = required_url(task_id, "model_url", output.model_url.as_deref())?;
|
||||
let rendered_image_url = required_url(
|
||||
task_id,
|
||||
"rendered_image_url",
|
||||
output.rendered_image_url.as_deref(),
|
||||
)?;
|
||||
|
||||
let rendered_image_url = output
|
||||
.rendered_image_url
|
||||
.as_ref()
|
||||
.or(output.rendered_image.as_ref())
|
||||
.map(|value| parse_url(value, task_id))
|
||||
.transpose()?;
|
||||
let generated_image_url = output
|
||||
.generated_image_url
|
||||
.as_ref()
|
||||
.map(|value| parse_url(value, task_id))
|
||||
.transpose()?;
|
||||
|
||||
Ok(TripoTaskOutput {
|
||||
model_urls,
|
||||
rendered_image_url,
|
||||
generated_image_url,
|
||||
})
|
||||
match task_type {
|
||||
TripoTaskType::TextToModel => Ok(TripoTaskOutput::TextToModel(TripoTextToModelResult {
|
||||
model_url,
|
||||
rendered_image_url,
|
||||
generated_image_url: required_url(
|
||||
task_id,
|
||||
"generated_image_url",
|
||||
output.generated_image_url.as_deref(),
|
||||
)?,
|
||||
})),
|
||||
TripoTaskType::ImageToModel => Ok(TripoTaskOutput::ImageToModel(TripoImageToModelResult {
|
||||
model_url,
|
||||
rendered_image_url,
|
||||
})),
|
||||
TripoTaskType::MultiviewToModel => Ok(TripoTaskOutput::MultiviewToModel(
|
||||
TripoMultiviewToModelResult {
|
||||
model_url,
|
||||
rendered_image_url,
|
||||
},
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_url(value: &str, task_id: &str) -> Result<TripoModelUrl, TripoError> {
|
||||
TripoModelUrl::parse(value).map_err(|error| match error {
|
||||
fn required_url(task_id: &str, field: &str, value: Option<&str>) -> Result<TripoUrl, TripoError> {
|
||||
let value = value.ok_or_else(|| TripoError::OutputSchema {
|
||||
task_id: task_id.into(),
|
||||
message: format!("completed task output is missing required {field}"),
|
||||
})?;
|
||||
parse_url(value, task_id)
|
||||
}
|
||||
|
||||
fn parse_url(value: &str, task_id: &str) -> Result<TripoUrl, TripoError> {
|
||||
TripoUrl::parse(value).map_err(|error| match error {
|
||||
TripoError::OutputSchema { message, .. } => TripoError::OutputSchema {
|
||||
task_id: task_id.into(),
|
||||
message,
|
||||
|
||||
@@ -10,8 +10,8 @@ pub use config::TripoSettings;
|
||||
pub use error::{TripoError, TripoField, TripoValidationReason};
|
||||
pub(crate) use mapping::map_task;
|
||||
pub use types::{
|
||||
TripoDownloadedModel, TripoModelUrl, TripoTaskFailure, TripoTaskHandle, TripoTaskOutput,
|
||||
TripoTaskSnapshot, TripoTaskType,
|
||||
TripoDownloadedModel, TripoTaskFailure, TripoTaskHandle, TripoTaskOutput, TripoTaskSnapshot,
|
||||
TripoTaskType, TripoUrl,
|
||||
};
|
||||
pub(crate) use validation::{
|
||||
TripoGenerationOptions, validate_generation_options, validate_task_id,
|
||||
|
||||
@@ -4,7 +4,11 @@ use url::Url;
|
||||
|
||||
use shared_contracts::model3d::common::Model3dTaskStatus;
|
||||
|
||||
use crate::common::TripoError;
|
||||
use crate::{
|
||||
common::TripoError, image_to_model::result::TripoImageToModelResult,
|
||||
multiview_to_model::result::TripoMultiviewToModelResult,
|
||||
text_to_model::result::TripoTextToModelResult,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TripoTaskHandle {
|
||||
@@ -19,18 +23,18 @@ pub enum TripoTaskType {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TripoModelUrl(Url);
|
||||
pub struct TripoUrl(Url);
|
||||
|
||||
impl TripoModelUrl {
|
||||
impl TripoUrl {
|
||||
pub(crate) fn parse(value: &str) -> Result<Self, TripoError> {
|
||||
let url = Url::parse(value).map_err(|error| TripoError::OutputSchema {
|
||||
task_id: "unknown".into(),
|
||||
message: format!("model URL is invalid: {error}"),
|
||||
message: format!("URL is invalid: {error}"),
|
||||
})?;
|
||||
if !matches!(url.scheme(), "http" | "https") {
|
||||
return Err(TripoError::OutputSchema {
|
||||
task_id: "unknown".into(),
|
||||
message: "model URL must use http or https".into(),
|
||||
message: "URL must use http or https".into(),
|
||||
});
|
||||
}
|
||||
Ok(Self(url))
|
||||
@@ -41,7 +45,7 @@ impl TripoModelUrl {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TripoModelUrl {
|
||||
impl fmt::Display for TripoUrl {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
@@ -54,12 +58,10 @@ pub struct TripoTaskFailure {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TripoTaskOutput {
|
||||
pub model_urls: Vec<TripoModelUrl>,
|
||||
pub rendered_image_url: Option<TripoModelUrl>,
|
||||
pub generated_image_url: Option<TripoModelUrl>,
|
||||
// TODO(tripo-docs): add fixed per-task output fields after the provider
|
||||
// contract is supplied and verified against real task responses.
|
||||
pub enum TripoTaskOutput {
|
||||
TextToModel(TripoTextToModelResult),
|
||||
ImageToModel(TripoImageToModelResult),
|
||||
MultiviewToModel(TripoMultiviewToModelResult),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
@@ -76,7 +78,7 @@ pub struct TripoTaskSnapshot {
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TripoDownloadedModel {
|
||||
pub url: TripoModelUrl,
|
||||
pub url: TripoUrl,
|
||||
pub content_type: Option<String>,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
mod client;
|
||||
pub mod result;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
use crate::common::TripoUrl;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TripoImageToModelResult {
|
||||
pub model_url: TripoUrl,
|
||||
pub rendered_image_url: TripoUrl,
|
||||
}
|
||||
@@ -4,12 +4,12 @@
|
||||
//! DTOs and `TripoError`, never `tripo3d_sdk` types or its poller API.
|
||||
|
||||
mod common;
|
||||
mod image_to_model;
|
||||
mod multiview_to_model;
|
||||
mod text_to_model;
|
||||
pub mod image_to_model;
|
||||
pub mod multiview_to_model;
|
||||
pub mod text_to_model;
|
||||
|
||||
pub use common::{
|
||||
TripoDownloadedModel, TripoError, TripoField, TripoModelUrl, TripoProviderClient,
|
||||
TripoSettings, TripoTaskFailure, TripoTaskHandle, TripoTaskOutput, TripoTaskSnapshot,
|
||||
TripoTaskType, TripoValidationReason,
|
||||
TripoDownloadedModel, TripoError, TripoField, TripoProviderClient, TripoSettings,
|
||||
TripoTaskFailure, TripoTaskHandle, TripoTaskOutput, TripoTaskSnapshot, TripoTaskType, TripoUrl,
|
||||
TripoValidationReason,
|
||||
};
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
mod client;
|
||||
pub mod result;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
use crate::common::TripoUrl;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TripoMultiviewToModelResult {
|
||||
pub model_url: TripoUrl,
|
||||
pub rendered_image_url: TripoUrl,
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
mod client;
|
||||
pub mod result;
|
||||
mod validation;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
use crate::common::TripoUrl;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TripoTextToModelResult {
|
||||
pub model_url: TripoUrl,
|
||||
pub rendered_image_url: TripoUrl,
|
||||
pub generated_image_url: TripoUrl,
|
||||
}
|
||||
Reference in New Issue
Block a user