mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
new endpoint
This commit is contained in:
1 parent
4fbf8625cc
commit
1e681a5825
7 files changed
+321
-1
No files matched your search
+56
@@ -0,0 +1,56 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub const FLUX_2_LORA_EDIT_IMAGE_ANGLE_PATH: &str = "/v1/generate/image/angle/flux_2_lora";
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||
pub struct Flux2LoraEditImageAngleRequest {
|
||||
/// Idempotency token to prevent duplicate requests.
|
||||
pub uuid_idempotency_token: String,
|
||||
|
||||
/// The image to edit with angle adjustment.
|
||||
pub image_media_token: MediaFileToken,
|
||||
|
||||
/// Horizontal rotation angle in degrees.
|
||||
pub horizontal_angle: Option<f64>,
|
||||
|
||||
/// Vertical rotation angle in degrees.
|
||||
pub vertical_angle: Option<f64>,
|
||||
|
||||
/// Zoom level.
|
||||
pub zoom: Option<f64>,
|
||||
|
||||
/// Number of images to generate. Default is one.
|
||||
pub num_images: Option<Flux2LoraEditImageAngleNumImages>,
|
||||
|
||||
/// Output image size. Default is square_hd.
|
||||
pub image_size: Option<Flux2LoraEditImageAngleImageSize>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Flux2LoraEditImageAngleNumImages {
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Flux2LoraEditImageAngleImageSize {
|
||||
Square,
|
||||
SquareHd,
|
||||
PortraitFourThree,
|
||||
PortraitSixteenNine,
|
||||
LandscapeFourThree,
|
||||
LandscapeSixteenNine,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct Flux2LoraEditImageAngleResponse {
|
||||
pub success: bool,
|
||||
pub inference_job_token: InferenceJobToken,
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod flux_2_lora_edit_image_angle;
|
||||
pub mod qwen_edit_2511_edit_image_angle;
|
||||
@@ -27,6 +27,8 @@ pub enum ModelType {
|
||||
FluxPro11Ultra,
|
||||
#[serde(rename = "flux_pro_kontext_max")]
|
||||
FluxProKontextMax,
|
||||
#[serde(rename = "flux_2_lora_angles")]
|
||||
Flux2LoraAngles,
|
||||
#[serde(rename = "gpt_image_1")]
|
||||
GptImage1,
|
||||
#[serde(rename = "gpt_image_1p5")]
|
||||
@@ -154,6 +156,7 @@ impl ModelType {
|
||||
Self::FluxPro11 => "flux_pro_1p1",
|
||||
Self::FluxPro11Ultra => "flux_pro_1p1_ultra",
|
||||
Self::FluxProKontextMax => "flux_pro_kontext_max",
|
||||
Self::Flux2LoraAngles => "flux_2_lora_angles",
|
||||
Self::GptImage1 => "gpt_image_1",
|
||||
Self::GptImage1p5 => "gpt_image_1p5",
|
||||
Self::GrokImage => "grok_image",
|
||||
@@ -219,6 +222,7 @@ impl ModelType {
|
||||
"flux_pro_1p1" => Ok(Self::FluxPro11),
|
||||
"flux_pro_1p1_ultra" => Ok(Self::FluxPro11Ultra),
|
||||
"flux_pro_kontext_max" => Ok(Self::FluxProKontextMax),
|
||||
"flux_2_lora_angles" => Ok(Self::Flux2LoraAngles),
|
||||
"gpt_image_1" => Ok(Self::GptImage1),
|
||||
"gpt_image_1p5" => Ok(Self::GptImage1p5),
|
||||
"grok_image" => Ok(Self::GrokImage),
|
||||
@@ -288,6 +292,7 @@ impl ModelType {
|
||||
Self::FluxPro11,
|
||||
Self::FluxPro11Ultra,
|
||||
Self::FluxProKontextMax,
|
||||
Self::Flux2LoraAngles,
|
||||
Self::GptImage1,
|
||||
Self::GptImage1p5,
|
||||
Self::GrokImage,
|
||||
@@ -362,6 +367,7 @@ mod tests {
|
||||
assert_serialization(ModelType::FluxPro11, "flux_pro_1p1");
|
||||
assert_serialization(ModelType::FluxPro11Ultra, "flux_pro_1p1_ultra");
|
||||
assert_serialization(ModelType::FluxProKontextMax, "flux_pro_kontext_max");
|
||||
assert_serialization(ModelType::Flux2LoraAngles, "flux_2_lora_angles");
|
||||
assert_serialization(ModelType::GptImage1, "gpt_image_1");
|
||||
assert_serialization(ModelType::GptImage1p5, "gpt_image_1p5");
|
||||
assert_serialization(ModelType::GrokImage, "grok_image");
|
||||
@@ -423,6 +429,7 @@ mod tests {
|
||||
assert_eq!(ModelType::FluxPro11.to_str(), "flux_pro_1p1");
|
||||
assert_eq!(ModelType::FluxPro11Ultra.to_str(), "flux_pro_1p1_ultra");
|
||||
assert_eq!(ModelType::FluxProKontextMax.to_str(), "flux_pro_kontext_max");
|
||||
assert_eq!(ModelType::Flux2LoraAngles.to_str(), "flux_2_lora_angles");
|
||||
assert_eq!(ModelType::GptImage1.to_str(), "gpt_image_1");
|
||||
assert_eq!(ModelType::GptImage1p5.to_str(), "gpt_image_1p5");
|
||||
assert_eq!(ModelType::GrokImage.to_str(), "grok_image");
|
||||
@@ -486,6 +493,7 @@ mod tests {
|
||||
assert_eq!(ModelType::from_str("flux_pro_1p1").unwrap(), ModelType::FluxPro11);
|
||||
assert_eq!(ModelType::from_str("flux_pro_1p1_ultra").unwrap(), ModelType::FluxPro11Ultra);
|
||||
assert_eq!(ModelType::from_str("flux_pro_kontext_max").unwrap(), ModelType::FluxProKontextMax);
|
||||
assert_eq!(ModelType::from_str("flux_2_lora_angles").unwrap(), ModelType::Flux2LoraAngles);
|
||||
assert_eq!(ModelType::from_str("gpt_image_1").unwrap(), ModelType::GptImage1);
|
||||
assert_eq!(ModelType::from_str("gpt_image_1p5").unwrap(), ModelType::GptImage1p5);
|
||||
assert_eq!(ModelType::from_str("grok_image").unwrap(), ModelType::GrokImage);
|
||||
@@ -541,7 +549,7 @@ mod tests {
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = ModelType::all_variants();
|
||||
assert_eq!(variants.len(), 53);
|
||||
assert_eq!(variants.len(), 54);
|
||||
// Image models
|
||||
assert_eq!(variants.pop_first(), Some(ModelType::Flux1Dev));
|
||||
assert_eq!(variants.pop_first(), Some(ModelType::Flux1Schnell));
|
||||
@@ -550,6 +558,7 @@ mod tests {
|
||||
assert_eq!(variants.pop_first(), Some(ModelType::FluxPro11));
|
||||
assert_eq!(variants.pop_first(), Some(ModelType::FluxPro11Ultra));
|
||||
assert_eq!(variants.pop_first(), Some(ModelType::FluxProKontextMax));
|
||||
assert_eq!(variants.pop_first(), Some(ModelType::Flux2LoraAngles));
|
||||
assert_eq!(variants.pop_first(), Some(ModelType::GptImage1));
|
||||
assert_eq!(variants.pop_first(), Some(ModelType::GptImage1p5));
|
||||
assert_eq!(variants.pop_first(), Some(ModelType::GrokImage));
|
||||
|
||||
@@ -241,6 +241,7 @@ use artcraft_api_defs::generate::image::multi_function::bytedance_seedream_v4_mu
|
||||
use artcraft_api_defs::generate::image::multi_function::bytedance_seedream_v4p5_multi_function_image_gen::*;
|
||||
use artcraft_api_defs::generate::image::multi_function::bytedance_seedream_5_lite_multi_function_image_gen::*;
|
||||
// Image edit (missing handlers)
|
||||
use artcraft_api_defs::generate::image::angle::flux_2_lora_edit_image_angle::*;
|
||||
use artcraft_api_defs::generate::image::angle::qwen_edit_2511_edit_image_angle::*;
|
||||
use artcraft_api_defs::generate::image::edit::flux_pro_kontext_max_edit_image::*;
|
||||
use artcraft_api_defs::generate::image::edit::gemini_25_flash_edit_image::*;
|
||||
@@ -427,6 +428,7 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
|
||||
crate::http_server::endpoints::generate::image::edit::qwen_edit_image_handler::qwen_edit_image_handler,
|
||||
crate::http_server::endpoints::generate::image::edit::seededit_3_edit_image_handler::seededit_3_edit_image_handler,
|
||||
// Generate Images (Angle)
|
||||
crate::http_server::endpoints::generate::image::angle::flux_2_lora_edit_image_angle_handler::flux_2_lora_edit_image_angle_handler,
|
||||
crate::http_server::endpoints::generate::image::angle::qwen_edit_2511_edit_image_angle_handler::qwen_edit_2511_edit_image_angle_handler,
|
||||
// Generate Images (Inpaint)
|
||||
crate::http_server::endpoints::generate::image::inpaint::flux_dev_juggernaut_inpaint_handler::flux_dev_juggernaut_inpaint_image_handler,
|
||||
@@ -1008,6 +1010,10 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
|
||||
BytedanceSeedream5LiteMultiFunctionImageGenNumImages,
|
||||
|
||||
// Image Angle types
|
||||
Flux2LoraEditImageAngleRequest,
|
||||
Flux2LoraEditImageAngleResponse,
|
||||
Flux2LoraEditImageAngleNumImages,
|
||||
Flux2LoraEditImageAngleImageSize,
|
||||
QwenEdit2511EditImageAngleRequest,
|
||||
QwenEdit2511EditImageAngleResponse,
|
||||
QwenEdit2511EditImageAngleNumImages,
|
||||
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::billing::wallets::attempt_wallet_deduction::attempt_wallet_deduction_else_common_web_error;
|
||||
use crate::http_server::common_responses::common_web_error::CommonWebError;
|
||||
use crate::http_server::endpoint_helpers::refund_wallet_after_api_failure::refund_wallet_after_api_failure;
|
||||
use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format;
|
||||
use crate::state::server_state::ServerState;
|
||||
use crate::util::lookup::lookup_image_urls_as_optional_list::lookup_image_urls_as_optional_list;
|
||||
use actix_web::web::Json;
|
||||
use actix_web::{web, HttpRequest};
|
||||
use artcraft_api_defs::generate::image::angle::flux_2_lora_edit_image_angle::{Flux2LoraEditImageAngleImageSize, Flux2LoraEditImageAngleNumImages, Flux2LoraEditImageAngleRequest, Flux2LoraEditImageAngleResponse};
|
||||
use enums::by_table::prompt_context_items::prompt_context_semantic_type::PromptContextSemanticType;
|
||||
use enums::by_table::prompts::prompt_type::PromptType;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::common::model_type::ModelType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use fal_client::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator;
|
||||
use fal_client::requests::webhook::image::angle::enqueue_flux_2_lora_edit_image_angle_webhook::{enqueue_flux_2_lora_edit_image_angle_webhook, EnqueueFlux2LoraEditImageAngleArgs, EnqueueFlux2LoraAngleNumImages, EnqueueFlux2LoraAngleImageSize};
|
||||
use http_server_common::request::get_request_ip::get_request_ip;
|
||||
use log::{error, info, warn};
|
||||
use mysql_queries::queries::generic_inference::fal::insert_generic_inference_job_for_fal_queue::FalCategory;
|
||||
use mysql_queries::queries::generic_inference::fal::insert_generic_inference_job_for_fal_queue_with_apriori_job_token::{insert_generic_inference_job_for_fal_queue_with_apriori_job_token, InsertGenericInferenceForFalWithAprioriJobTokenArgs};
|
||||
use mysql_queries::queries::idepotency_tokens::insert_idempotency_token::insert_idempotency_token;
|
||||
use mysql_queries::queries::prompt_context_items::insert_batch_prompt_context_items::{insert_batch_prompt_context_items, InsertBatchArgs, PromptContextItem};
|
||||
use mysql_queries::queries::prompts::insert_prompt::{insert_prompt, InsertPromptArgs};
|
||||
use sqlx::Acquire;
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
|
||||
/// Flux 2 LoRA - Edit Image Angle
|
||||
#[utoipa::path(
|
||||
post,
|
||||
tag = "Generate Images (Angle)",
|
||||
path = "/v1/generate/image/angle/flux_2_lora",
|
||||
responses(
|
||||
(status = 200, description = "Success", body = Flux2LoraEditImageAngleResponse),
|
||||
),
|
||||
params(
|
||||
("request" = Flux2LoraEditImageAngleRequest, description = "Payload for Request"),
|
||||
)
|
||||
)]
|
||||
pub async fn flux_2_lora_edit_image_angle_handler(
|
||||
http_request: HttpRequest,
|
||||
request: Json<Flux2LoraEditImageAngleRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<Json<Flux2LoraEditImageAngleResponse>, CommonWebError> {
|
||||
|
||||
if let Err(reason) = validate_idempotency_token_format(&request.uuid_idempotency_token) {
|
||||
return Err(CommonWebError::BadInputWithSimpleMessage(reason));
|
||||
}
|
||||
|
||||
let mut mysql_connection = server_state.mysql_pool
|
||||
.acquire()
|
||||
.await?;
|
||||
|
||||
let maybe_user_session = server_state
|
||||
.session_checker
|
||||
.maybe_get_user_session_from_connection(&http_request, &mut mysql_connection)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Session checker error: {:?}", e);
|
||||
CommonWebError::ServerError
|
||||
})?;
|
||||
|
||||
let maybe_avt_token = server_state
|
||||
.avt_cookie_manager
|
||||
.get_avt_token_from_request(&http_request);
|
||||
|
||||
let user_token = match maybe_user_session.as_ref() {
|
||||
Some(session) => &session.user_token,
|
||||
None => {
|
||||
return Err(CommonWebError::NotAuthorized);
|
||||
}
|
||||
};
|
||||
|
||||
let media_tokens = vec![request.image_media_token.clone()];
|
||||
|
||||
let image_urls = lookup_image_urls_as_optional_list(
|
||||
&http_request,
|
||||
&mut mysql_connection,
|
||||
server_state.server_environment,
|
||||
&media_tokens,
|
||||
).await?
|
||||
.ok_or_else(|| {
|
||||
warn!("No image URLs found for media token");
|
||||
CommonWebError::BadInputWithSimpleMessage("Image media token not found".to_string())
|
||||
})?;
|
||||
|
||||
insert_idempotency_token(&request.uuid_idempotency_token, &mut *mysql_connection)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error inserting idempotency token: {:?}", err);
|
||||
CommonWebError::BadInputWithSimpleMessage("repeated idempotency token".to_string())
|
||||
})?;
|
||||
|
||||
info!("Fal webhook URL: {}", server_state.fal.webhook_url);
|
||||
|
||||
let apriori_job_token = InferenceJobToken::generate();
|
||||
|
||||
let num_images = request.num_images.map(|n| match n {
|
||||
Flux2LoraEditImageAngleNumImages::One => EnqueueFlux2LoraAngleNumImages::One,
|
||||
Flux2LoraEditImageAngleNumImages::Two => EnqueueFlux2LoraAngleNumImages::Two,
|
||||
Flux2LoraEditImageAngleNumImages::Three => EnqueueFlux2LoraAngleNumImages::Three,
|
||||
Flux2LoraEditImageAngleNumImages::Four => EnqueueFlux2LoraAngleNumImages::Four,
|
||||
});
|
||||
|
||||
let image_size = request.image_size.map(|s| match s {
|
||||
Flux2LoraEditImageAngleImageSize::Square => EnqueueFlux2LoraAngleImageSize::Square,
|
||||
Flux2LoraEditImageAngleImageSize::SquareHd => EnqueueFlux2LoraAngleImageSize::SquareHd,
|
||||
Flux2LoraEditImageAngleImageSize::PortraitFourThree => EnqueueFlux2LoraAngleImageSize::PortraitFourThree,
|
||||
Flux2LoraEditImageAngleImageSize::PortraitSixteenNine => EnqueueFlux2LoraAngleImageSize::PortraitSixteenNine,
|
||||
Flux2LoraEditImageAngleImageSize::LandscapeFourThree => EnqueueFlux2LoraAngleImageSize::LandscapeFourThree,
|
||||
Flux2LoraEditImageAngleImageSize::LandscapeSixteenNine => EnqueueFlux2LoraAngleImageSize::LandscapeSixteenNine,
|
||||
});
|
||||
|
||||
let args = EnqueueFlux2LoraEditImageAngleArgs {
|
||||
image_urls,
|
||||
horizontal_angle: request.horizontal_angle,
|
||||
vertical_angle: request.vertical_angle,
|
||||
zoom: request.zoom,
|
||||
num_images,
|
||||
image_size,
|
||||
lora_scale: None,
|
||||
guidance_scale: None,
|
||||
num_inference_steps: None,
|
||||
webhook_url: &server_state.fal.webhook_url,
|
||||
api_key: &server_state.fal.api_key,
|
||||
};
|
||||
|
||||
let cost = args.calculate_cost_in_cents();
|
||||
|
||||
info!("Charging wallet: {}", cost);
|
||||
|
||||
let wallet_deduction = attempt_wallet_deduction_else_common_web_error(
|
||||
user_token,
|
||||
Some(apriori_job_token.as_str()),
|
||||
cost,
|
||||
&mut mysql_connection,
|
||||
).await?;
|
||||
|
||||
let fal_result = match enqueue_flux_2_lora_edit_image_angle_webhook(args).await {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
warn!("Error calling enqueue_flux_2_lora_edit_image_angle_webhook: {:?}", err);
|
||||
refund_wallet_after_api_failure(&wallet_deduction.ledger_entry_token, &mut mysql_connection).await?;
|
||||
return Err(CommonWebError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let external_job_id = fal_result.request_id
|
||||
.ok_or_else(|| {
|
||||
warn!("Fal request_id is None");
|
||||
CommonWebError::ServerError
|
||||
})?;
|
||||
|
||||
info!("Fal request_id: {}", external_job_id);
|
||||
|
||||
let ip_address = get_request_ip(&http_request);
|
||||
|
||||
let mut transaction = mysql_connection
|
||||
.begin()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error starting MySQL transaction: {:?}", err);
|
||||
CommonWebError::ServerError
|
||||
})?;
|
||||
|
||||
let prompt_result = insert_prompt(InsertPromptArgs {
|
||||
maybe_apriori_prompt_token: None,
|
||||
prompt_type: PromptType::ArtcraftApp,
|
||||
maybe_creator_user_token: Some(&user_token),
|
||||
maybe_model_type: Some(ModelType::Flux2LoraAngles),
|
||||
maybe_generation_provider: Some(GenerationProvider::Artcraft),
|
||||
maybe_positive_prompt: None,
|
||||
maybe_negative_prompt: None,
|
||||
maybe_other_args: None,
|
||||
creator_ip_address: &ip_address,
|
||||
mysql_executor: &mut *transaction,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
let prompt_token = match prompt_result {
|
||||
Ok(token) => Some(token),
|
||||
Err(err) => {
|
||||
warn!("Error inserting prompt: {:?}", err);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(token) = prompt_token.as_ref() {
|
||||
let result = insert_batch_prompt_context_items(InsertBatchArgs {
|
||||
prompt_token: token.clone(),
|
||||
items: media_tokens.iter().map(|token| {
|
||||
PromptContextItem {
|
||||
media_token: token.clone(),
|
||||
context_semantic_type: PromptContextSemanticType::Imgsrc,
|
||||
}
|
||||
}).collect(),
|
||||
transaction: &mut transaction,
|
||||
}).await;
|
||||
|
||||
if let Err(err) = result {
|
||||
warn!("Error inserting batch prompt context items: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let db_result = insert_generic_inference_job_for_fal_queue_with_apriori_job_token(InsertGenericInferenceForFalWithAprioriJobTokenArgs {
|
||||
apriori_job_token: &apriori_job_token,
|
||||
uuid_idempotency_token: &request.uuid_idempotency_token,
|
||||
maybe_external_third_party_id: &external_job_id,
|
||||
fal_category: FalCategory::ImageGeneration,
|
||||
maybe_inference_args: None,
|
||||
maybe_prompt_token: prompt_token.as_ref(),
|
||||
maybe_creator_user_token: Some(&user_token),
|
||||
maybe_avt_token: maybe_avt_token.as_ref(),
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
let job_token = match db_result {
|
||||
Ok(token) => token,
|
||||
Err(err) => {
|
||||
warn!("Error inserting generic inference job for FAL queue: {:?}", err);
|
||||
return Err(CommonWebError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let _r = transaction
|
||||
.commit()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error committing MySQL transaction: {:?}", err);
|
||||
CommonWebError::ServerError
|
||||
})?;
|
||||
|
||||
Ok(Json(Flux2LoraEditImageAngleResponse {
|
||||
success: true,
|
||||
inference_job_token: job_token,
|
||||
}))
|
||||
}
|
||||
+1
@@ -1 +1,2 @@
|
||||
pub mod flux_2_lora_edit_image_angle_handler;
|
||||
pub mod qwen_edit_2511_edit_image_angle_handler;
|
||||
+5
@@ -20,6 +20,7 @@ use crate::http_server::endpoints::generate::image::multi_function::gpt_image_1p
|
||||
use crate::http_server::endpoints::generate::image::multi_function::nano_banana_2_multi_function_image_gen_handler::nano_banana_2_multi_function_image_gen_handler;
|
||||
use crate::http_server::endpoints::generate::image::multi_function::nano_banana_multi_function_image_gen_handler::nano_banana_multi_function_image_gen_handler;
|
||||
use crate::http_server::endpoints::generate::image::multi_function::nano_banana_pro_multi_function_image_gen_handler::nano_banana_pro_multi_function_image_gen_handler;
|
||||
use crate::http_server::endpoints::generate::image::angle::flux_2_lora_edit_image_angle_handler::flux_2_lora_edit_image_angle_handler;
|
||||
use crate::http_server::endpoints::generate::image::angle::qwen_edit_2511_edit_image_angle_handler::qwen_edit_2511_edit_image_angle_handler;
|
||||
use crate::http_server::endpoints::generate::image::remove_image_background_handler::remove_image_background_handler;
|
||||
use crate::http_server::endpoints::generate::object::generate_hunyuan_2_0_image_to_3d_handler::generate_hunyuan_2_0_image_to_3d_handler;
|
||||
@@ -140,6 +141,10 @@ where
|
||||
)
|
||||
)
|
||||
.service(web::scope("/angle")
|
||||
.service(web::resource("/flux_2_lora")
|
||||
.route(web::post().to(flux_2_lora_edit_image_angle_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
.service(web::resource("/qwen_edit_2511")
|
||||
.route(web::post().to(qwen_edit_2511_edit_image_angle_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
|
||||
Reference in new issue
Block a user