diff --git a/server-rs/crates/api-server/src/tripo3d/result.rs b/server-rs/crates/api-server/src/tripo3d/result.rs index c93f1b754..63a38fbbc 100644 --- a/server-rs/crates/api-server/src/tripo3d/result.rs +++ b/server-rs/crates/api-server/src/tripo3d/result.rs @@ -3,13 +3,16 @@ //! 结果按端点使用严格 tagged enum,只带正式资源引用与已落地对象元数据; //! provider task ID、带签名的临时地址与 SDK 类型都不进入结果。 +use axum::http::StatusCode; use serde_json::{Value, json}; use shared_contracts::model3d::Model3dGenerationResult; use shared_contracts::model3d::common::{Model3dGeneratedArtifact, Model3dGenerationTargetRef}; use shared_contracts::model3d::image_to_model::Model3dImageToModelResult; use shared_contracts::model3d::text_to_model::Model3dTextToModelResult; -use super::{job::Model3dJobKind, storage::StoredModel3dArtifact}; +use crate::http_error::AppError; + +use super::{job::Model3dJobKind, provider::TRIPO_PROVIDER, storage::StoredModel3dArtifact}; pub(crate) fn artifact_metadata(stored: &StoredModel3dArtifact) -> Model3dGeneratedArtifact { Model3dGeneratedArtifact { @@ -47,13 +50,15 @@ pub(crate) fn build_result( } /// 队列终态结果载荷:外层固定 `result` 字段,值就是严格类型化的完成结果。 -pub(crate) fn job_result_payload(result: Model3dGenerationResult) -> Value { - match serde_json::to_value(result) { - Ok(value) => json!({ "result": value }), - // 结果由字符串与数字组成,序列化失败属于实现错误;仍返回可对账的稳定形状。 - Err(error) => json!({ - "result": null, - "resultSerializeError": error.to_string(), - }), - } +/// +/// 序列化失败按服务端问题上报,由 worker 把任务标记为失败 —— 不能落一条 +/// 「完成但 `result: null`」的终态,消费方会当成成功却反序列化不出结果。 +pub(crate) fn job_result_payload(result: Model3dGenerationResult) -> Result { + let value = serde_json::to_value(result).map_err(|error| { + AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_details(json!({ + "provider": TRIPO_PROVIDER, + "message": format!("序列化 3D 生成结果失败:{error}"), + })) + })?; + Ok(json!({ "result": value })) } diff --git a/server-rs/crates/api-server/src/tripo3d/worker.rs b/server-rs/crates/api-server/src/tripo3d/worker.rs index 662822a0e..d73b479de 100644 --- a/server-rs/crates/api-server/src/tripo3d/worker.rs +++ b/server-rs/crates/api-server/src/tripo3d/worker.rs @@ -365,7 +365,7 @@ async fn persist_result( _ => EditorCanvasLayoutPlan::None, }; let job_result_payload_json = - editor_generation_job_result_payload_json(caller, job_result_payload(result)); + editor_generation_job_result_payload_json(caller, job_result_payload(result)?); persist_editor_generation_result_atomically( state, caller, @@ -499,7 +499,7 @@ mod tests { &model, &preview, ); - let payload = job_result_payload(result); + let payload = job_result_payload(result).expect("完成结果应可序列化"); let result = &payload["result"]; assert_eq!(result["kind"], json!(expected_kind));