hunyuan 3d 2.1

This commit is contained in:
Brandon Thomas committed 2025-06-15 18:55:26 -04:00
1 parent a9c038995c
commit 55aa978943
6 files changed
+152 -15

No files matched your search

@@ -0,0 +1,65 @@
use crate::creds::fal_api_key::FalApiKey;
use crate::error::classify_fal_error::classify_fal_error;
use crate::error::fal_error_plus::FalErrorPlus;
use fal::prelude::fal_ai::hunyuan3d::v21::{v21, Hunyuan3DInput};
use fal::webhook::WebhookResponse;
use reqwest::IntoUrl;
pub struct Hunyuan3d21Args<'a, U: IntoUrl, V: IntoUrl> {
pub image_url: U,
pub webhook_url: V,
pub api_key: &'a FalApiKey,
}
pub async fn enqueue_hunyuan_3d_2_1_image_to_3d_webhook<U: IntoUrl, V: IntoUrl>(
args: Hunyuan3d21Args<'_, U, V>
) -> Result<WebhookResponse, FalErrorPlus> {
let image_url = args.image_url.as_str().to_string();
let request = Hunyuan3DInput {
input_image_url: image_url,
textured_mesh: Some(true),
// TODO: Maybe expose these later
guidance_scale: None,
num_inference_steps: None,
octree_resolution: None,
seed: None,
};
let result = v21(request)
.with_api_key(&args.api_key.0)
.queue_webhook(args.webhook_url)
.await;
result.map_err(|err| classify_fal_error(err))
}
#[cfg(test)]
mod tests {
use crate::creds::fal_api_key::FalApiKey;
use crate::requests::webhook::object::enqueue_hunyuan_3d_21_image_to_3d_webhook::{enqueue_hunyuan_3d_2_1_image_to_3d_webhook, Hunyuan3d21Args};
use errors::AnyhowResult;
use std::fs::read_to_string;
#[tokio::test]
#[ignore]
async fn test_hunyuan3d_21() -> AnyhowResult<()> {
let image_url = "https://cdn-2.fakeyou.com/media/p/a/c/7/j/pac7jgp2tkehm7j7sm4sky1fpnkrnbve/image_pac7jgp2tkehm7j7sm4sky1fpnkrnbve.png";
// XXX: Don't commit secrets!
let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?;
let api_key = FalApiKey::from_str(&secret);
let args = Hunyuan3d21Args {
image_url: image_url,
api_key: &api_key,
webhook_url: "https://example.com/webhook",
};
let result = enqueue_hunyuan_3d_2_1_image_to_3d_webhook(args).await?;
Ok(())
}
}
@@ -5,21 +5,14 @@ use fal::endpoints::fal_ai::hunyuan3d::v2::{v2, Hunyuan3DInput};
use fal::webhook::WebhookResponse;
use reqwest::IntoUrl;
pub struct Hunyuan2Args<'a, U: IntoUrl, V: IntoUrl> {
pub struct Hunyuan3d2Args<'a, U: IntoUrl, V: IntoUrl> {
pub image_url: U,
pub webhook_url: V,
pub api_key: &'a FalApiKey,
}
#[derive(Copy, Clone, Debug)]
pub enum Kling16Duration {
Default,
FiveSeconds,
TenSeconds,
}
pub async fn enqueue_hunyuan2_image_to_3d_webhook<U: IntoUrl, V: IntoUrl>(
args: Hunyuan2Args<'_, U, V>
pub async fn enqueue_hunyuan_3d_2_image_to_3d_webhook<U: IntoUrl, V: IntoUrl>(
args: Hunyuan3d2Args<'_, U, V>
) -> Result<WebhookResponse, FalErrorPlus> {
let image_url = args.image_url.as_str().to_string();
@@ -1 +1,2 @@
pub mod enqueue_hunyuan2_image_to_3d_webhook;
pub mod enqueue_hunyuan_3d_2_image_to_3d_webhook;
pub mod enqueue_hunyuan_3d_21_image_to_3d_webhook;
@@ -19,8 +19,8 @@ use artcraft_api_defs::generate::object::generate_hunyuan_2_image_to_3d::Generat
use artcraft_api_defs::generate::object::generate_hunyuan_2_image_to_3d::GenerateHunyuan2ImageTo3dResponse;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use enums::common::visibility::Visibility;
use fal_client::requests::webhook::object::enqueue_hunyuan2_image_to_3d_webhook::enqueue_hunyuan2_image_to_3d_webhook;
use fal_client::requests::webhook::object::enqueue_hunyuan2_image_to_3d_webhook::Hunyuan2Args;
use fal_client::requests::webhook::object::enqueue_hunyuan_3d_2_image_to_3d_webhook::enqueue_hunyuan_3d_2_image_to_3d_webhook;
use fal_client::requests::webhook::object::enqueue_hunyuan_3d_2_image_to_3d_webhook::Hunyuan3d2Args;
use http_server_common::request::get_request_ip::get_request_ip;
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
use idempotency::uuid::generate_random_uuid;
@@ -167,13 +167,13 @@ pub async fn generate_hunyuan_2_image_to_3d_handler(
info!("Fal webhook URL: {}", server_state.fal.webhook_url);
let args = Hunyuan2Args {
let args = Hunyuan3d2Args {
image_url: media_links.cdn_url,
webhook_url: &server_state.fal.webhook_url,
api_key: &server_state.fal.api_key,
};
let fal_result = enqueue_hunyuan2_image_to_3d_webhook(args)
let fal_result = enqueue_hunyuan_3d_2_image_to_3d_webhook(args)
.await
.map_err(|err| {
warn!("Error calling enqueue_hunyuan2_image_to_3d_webhook: {:?}", err);
@@ -12,3 +12,17 @@
)))
)]
pub mod v2;
#[cfg(any(
feature = "endpoints",
feature = "endpoints_fal-ai",
feature = "endpoints_fal-ai_hunyuan3d"
))]
#[cfg_attr(
docsrs,
doc(cfg(any(
feature = "endpoints",
feature = "endpoints_fal-ai",
feature = "endpoints_fal-ai_hunyuan3d"
)))
)]
pub mod v21;
@@ -0,0 +1,64 @@
use crate::prelude::FalRequest;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct Hunyuan3DInput {
/// Guidance scale for the model.
#[serde(skip_serializing_if = "Option::is_none")]
pub guidance_scale: Option<f64>,
/// URL of image to use while generating the 3D model.
/// "https://storage.googleapis.com/falserverless/model_tests/video_models/robot.png"
pub input_image_url: String,
/// Number of inference steps to perform.
#[serde(skip_serializing_if = "Option::is_none")]
pub num_inference_steps: Option<i64>,
/// Octree resolution for the model.
#[serde(skip_serializing_if = "Option::is_none")]
pub octree_resolution: Option<i64>,
/// The same seed and the same prompt given to the same version of the model
/// will output the same image every time.
#[serde(skip_serializing_if = "Option::is_none")]
pub seed: Option<i64>,
/// If set true, textured mesh will be generated and the price charged would be 3 times that of white mesh.
#[serde(skip_serializing_if = "Option::is_none")]
pub textured_mesh: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ObjectOutput {
/// Generated 3D object file.
/// {"content_type":"application/octet-stream","file_name":"white_mesh.glb","file_size":720696,"url":"https://v3.fal.media/files/lion/WqIhtKPaSoeBtC30qzIGG_white_mesh.glb"}
pub model_mesh: File,
/// Seed value used for generation.
pub seed: i64,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct File {
/// The mime type of the file.
/// "image/png"
#[serde(skip_serializing_if = "Option::is_none")]
pub content_type: Option<String>,
/// File data
#[serde(skip_serializing_if = "Option::is_none")]
pub file_data: Option<String>,
/// The name of the file. It will be auto-generated if not provided.
/// "z9RV14K95DvU.png"
#[serde(skip_serializing_if = "Option::is_none")]
pub file_name: Option<String>,
/// The size of the file in bytes.
/// 4404019
#[serde(skip_serializing_if = "Option::is_none")]
pub file_size: Option<i64>,
/// The URL where the file can be downloaded from.
pub url: String,
}
/// Hunyuan3D
///
/// Category: image-to-3d
/// Machine Type: H100
/// License Type: commercial
pub fn v21(params: Hunyuan3DInput) -> FalRequest<Hunyuan3DInput, ObjectOutput> {
FalRequest::new("fal-ai/hunyuan3d-v21", params)
}