mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-08 11:01:35 +00:00
nano banana pro text to image
This commit is contained in:
1 parent
7723341b6c
commit
d78cca34f3
5 files changed
+235
No files matched your search
@@ -1,3 +1,4 @@
|
||||
pub mod flux_1_dev_text_to_image;
|
||||
pub mod flux_1_schnell_text_to_image;
|
||||
pub mod nano_banana_2_text_to_image;
|
||||
pub mod nano_banana_pro_text_to_image;
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
use crate::error::fal_error_plus::FalErrorPlus;
|
||||
use crate::requests::api::image::text::nano_banana_pro_text_to_image::raw_request::{
|
||||
NanoBananaProTextToImageInput, NanoBananaProTextToImageOutput,
|
||||
};
|
||||
use crate::requests::traits::fal_endpoint_trait::FalEndpoint;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NanoBananaProTextToImageRequest {
|
||||
/// Text prompt describing the image to generate.
|
||||
pub prompt: String,
|
||||
|
||||
/// Number of images to generate.
|
||||
pub num_images: NanoBananaProTextToImageNumImages,
|
||||
|
||||
/// Output resolution.
|
||||
pub resolution: Option<NanoBananaProTextToImageResolution>,
|
||||
|
||||
/// Aspect ratio.
|
||||
pub aspect_ratio: Option<NanoBananaProTextToImageAspectRatio>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum NanoBananaProTextToImageNumImages {
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum NanoBananaProTextToImageResolution {
|
||||
OneK,
|
||||
TwoK,
|
||||
FourK,
|
||||
}
|
||||
|
||||
/// 21:9, 16:9, 3:2, 4:3, 5:4, 1:1, 4:5, 3:4, 2:3, 9:16
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum NanoBananaProTextToImageAspectRatio {
|
||||
OneByOne,
|
||||
FiveByFour,
|
||||
FourByThree,
|
||||
ThreeByTwo,
|
||||
SixteenByNine,
|
||||
TwentyOneByNine,
|
||||
FourByFive,
|
||||
ThreeByFour,
|
||||
TwoByThree,
|
||||
NineBySixteen,
|
||||
}
|
||||
|
||||
impl FalEndpoint for NanoBananaProTextToImageRequest {
|
||||
const ENDPOINT: &str = "fal-ai/nano-banana-pro";
|
||||
|
||||
type RawRequest = NanoBananaProTextToImageInput;
|
||||
type RawResponse = NanoBananaProTextToImageOutput;
|
||||
|
||||
fn to_raw_request(&self) -> Result<Self::RawRequest, FalErrorPlus> {
|
||||
let num_images = match self.num_images {
|
||||
NanoBananaProTextToImageNumImages::One => 1,
|
||||
NanoBananaProTextToImageNumImages::Two => 2,
|
||||
NanoBananaProTextToImageNumImages::Three => 3,
|
||||
NanoBananaProTextToImageNumImages::Four => 4,
|
||||
};
|
||||
|
||||
let resolution = self.resolution.map(|r| match r {
|
||||
NanoBananaProTextToImageResolution::OneK => "1K",
|
||||
NanoBananaProTextToImageResolution::TwoK => "2K",
|
||||
NanoBananaProTextToImageResolution::FourK => "4K",
|
||||
}.to_string());
|
||||
|
||||
let aspect_ratio = self.aspect_ratio.map(|ar| match ar {
|
||||
NanoBananaProTextToImageAspectRatio::OneByOne => "1:1",
|
||||
NanoBananaProTextToImageAspectRatio::FiveByFour => "5:4",
|
||||
NanoBananaProTextToImageAspectRatio::FourByThree => "4:3",
|
||||
NanoBananaProTextToImageAspectRatio::ThreeByTwo => "3:2",
|
||||
NanoBananaProTextToImageAspectRatio::SixteenByNine => "16:9",
|
||||
NanoBananaProTextToImageAspectRatio::TwentyOneByNine => "21:9",
|
||||
NanoBananaProTextToImageAspectRatio::FourByFive => "4:5",
|
||||
NanoBananaProTextToImageAspectRatio::ThreeByFour => "3:4",
|
||||
NanoBananaProTextToImageAspectRatio::TwoByThree => "2:3",
|
||||
NanoBananaProTextToImageAspectRatio::NineBySixteen => "9:16",
|
||||
}.to_string());
|
||||
|
||||
Ok(Self::RawRequest {
|
||||
prompt: self.prompt.clone(),
|
||||
num_images: Some(num_images),
|
||||
aspect_ratio,
|
||||
resolution,
|
||||
output_format: Some("png".to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::requests::traits::fal_endpoint_trait::FalEndpoint;
|
||||
use errors::AnyhowResult;
|
||||
use std::fs::read_to_string;
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore] // manually test — requires real API key, incurs costs
|
||||
async fn test_text_to_image() -> AnyhowResult<()> {
|
||||
let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?;
|
||||
let api_key = FalApiKey::from_str(&secret);
|
||||
|
||||
let request = NanoBananaProTextToImageRequest {
|
||||
prompt: "an anime girl riding on the back of a t-rex".to_string(),
|
||||
num_images: NanoBananaProTextToImageNumImages::One,
|
||||
resolution: Some(NanoBananaProTextToImageResolution::TwoK),
|
||||
aspect_ratio: Some(NanoBananaProTextToImageAspectRatio::SixteenByNine),
|
||||
};
|
||||
|
||||
let result = request.send_webhook_request(&api_key, "https://example.com/test").await?;
|
||||
println!("Request ID: {:?}", result.request_id);
|
||||
assert!(result.request_id.is_some());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// NB: Pricing tests are in cost.rs
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
use crate::requests::api::image::text::nano_banana_pro_text_to_image::api::{
|
||||
NanoBananaProTextToImageNumImages, NanoBananaProTextToImageRequest,
|
||||
NanoBananaProTextToImageResolution,
|
||||
};
|
||||
use crate::requests::traits::fal_request_cost_calculator_trait::{FalRequestCostCalculator, UsdCents};
|
||||
|
||||
impl FalRequestCostCalculator for NanoBananaProTextToImageRequest {
|
||||
fn calculate_cost_in_cents(&self) -> UsdCents {
|
||||
// Your request will cost $0.15 per image.
|
||||
// 4K outputs will be charged at double the standard rate.
|
||||
let base_cost = match self.resolution {
|
||||
None => 15,
|
||||
Some(NanoBananaProTextToImageResolution::OneK) => 15,
|
||||
Some(NanoBananaProTextToImageResolution::TwoK) => 15,
|
||||
Some(NanoBananaProTextToImageResolution::FourK) => 30,
|
||||
};
|
||||
let cost = match self.num_images {
|
||||
NanoBananaProTextToImageNumImages::One => base_cost,
|
||||
NanoBananaProTextToImageNumImages::Two => base_cost * 2,
|
||||
NanoBananaProTextToImageNumImages::Three => base_cost * 3,
|
||||
NanoBananaProTextToImageNumImages::Four => base_cost * 4,
|
||||
};
|
||||
cost as UsdCents
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn make_request(
|
||||
num_images: NanoBananaProTextToImageNumImages,
|
||||
resolution: Option<NanoBananaProTextToImageResolution>,
|
||||
) -> NanoBananaProTextToImageRequest {
|
||||
NanoBananaProTextToImageRequest {
|
||||
prompt: "test".to_string(),
|
||||
num_images,
|
||||
resolution,
|
||||
aspect_ratio: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_default_resolution_one_image() {
|
||||
assert_eq!(make_request(NanoBananaProTextToImageNumImages::One, None).calculate_cost_in_cents(), 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_one_k_one_image() {
|
||||
assert_eq!(make_request(NanoBananaProTextToImageNumImages::One, Some(NanoBananaProTextToImageResolution::OneK)).calculate_cost_in_cents(), 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_two_k_one_image() {
|
||||
assert_eq!(make_request(NanoBananaProTextToImageNumImages::One, Some(NanoBananaProTextToImageResolution::TwoK)).calculate_cost_in_cents(), 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_four_k_one_image() {
|
||||
assert_eq!(make_request(NanoBananaProTextToImageNumImages::One, Some(NanoBananaProTextToImageResolution::FourK)).calculate_cost_in_cents(), 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_one_k_four_images() {
|
||||
assert_eq!(make_request(NanoBananaProTextToImageNumImages::Four, Some(NanoBananaProTextToImageResolution::OneK)).calculate_cost_in_cents(), 60);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cost_four_k_two_images() {
|
||||
assert_eq!(make_request(NanoBananaProTextToImageNumImages::Two, Some(NanoBananaProTextToImageResolution::FourK)).calculate_cost_in_cents(), 60);
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
pub mod api;
|
||||
mod raw_request;
|
||||
mod cost;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct NanoBananaProTextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Options: auto, 21:9, 16:9, 3:2, 4:3, 5:4, 1:1, 4:5, 3:4, 2:3, 9:16
|
||||
/// Default: "auto"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub aspect_ratio: Option<String>,
|
||||
|
||||
/// "1K", "2K", "4K"
|
||||
/// Default: "1K"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolution: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// "jpeg", "png", "webp"
|
||||
/// Default: "png"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct NanoBananaProTextToImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct NanoBananaProTextToImageOutput {
|
||||
pub images: Vec<NanoBananaProTextToImageFile>,
|
||||
}
|
||||
Reference in new issue
Block a user