mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-23 18:19:30 -04:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
638f958242 | ||
|
|
e93c8b728f |
@@ -14,4 +14,16 @@ pub enum CommonResolution {
|
||||
ThreeK,
|
||||
/// Models: Nano Banana Pro
|
||||
FourK,
|
||||
|
||||
/// Used by Nano Banana 2 (and others)
|
||||
HalfK,
|
||||
|
||||
/// Used by the Seedance family (and others)
|
||||
FourEightyP,
|
||||
|
||||
/// Used by the Seedance family (and others)
|
||||
SevenTwentyP,
|
||||
|
||||
/// Used by the Seedance family (and others)
|
||||
TenEightyP,
|
||||
}
|
||||
|
||||
+2
@@ -135,6 +135,8 @@ fn plan_resolution(
|
||||
// No 3K option; default to 2K
|
||||
Ok(Some(Nb2Res::TwoK))
|
||||
}
|
||||
// HalfK, FourEightyP, SevenTwentyP, TenEightyP — nearest supported is OneK
|
||||
Some(R::HalfK | R::FourEightyP | R::SevenTwentyP | R::TenEightyP) => Ok(Some(Nb2Res::OneK)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -135,6 +135,8 @@ fn plan_resolution(
|
||||
// No 3K option; default to 2K
|
||||
Ok(Some(NbpRes::TwoK))
|
||||
}
|
||||
// HalfK, FourEightyP, SevenTwentyP, TenEightyP — nearest supported is OneK
|
||||
Some(R::HalfK | R::FourEightyP | R::SevenTwentyP | R::TenEightyP) => Ok(Some(NbpRes::OneK)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -202,6 +202,11 @@ fn plan_resolution(
|
||||
Some(CommonResolution::FourK) => Ok(Some(FalNbpResolution::FourK)),
|
||||
// No 3K option; fall back to 2K
|
||||
Some(CommonResolution::ThreeK) => Ok(Some(FalNbpResolution::TwoK)),
|
||||
// Fall back to nearest supported resolution
|
||||
Some(CommonResolution::HalfK) => Ok(Some(FalNbpResolution::OneK)),
|
||||
Some(CommonResolution::FourEightyP) => Ok(Some(FalNbpResolution::OneK)),
|
||||
Some(CommonResolution::SevenTwentyP) => Ok(Some(FalNbpResolution::OneK)),
|
||||
Some(CommonResolution::TenEightyP) => Ok(Some(FalNbpResolution::OneK)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -167,6 +167,10 @@ fn plan_resolution(
|
||||
Some(CommonResolution::TwoK) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::TenEightyP)),
|
||||
Some(CommonResolution::ThreeK) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::TenEightyP)),
|
||||
Some(CommonResolution::FourK) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::TenEightyP)),
|
||||
// HalfK and FourEightyP map to the lowest supported resolution
|
||||
Some(CommonResolution::HalfK | CommonResolution::FourEightyP) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::FourEightyP)),
|
||||
Some(CommonResolution::SevenTwentyP) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::SevenTwentyP)),
|
||||
Some(CommonResolution::TenEightyP) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::TenEightyP)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,4 +14,16 @@ pub enum CommonResolution {
|
||||
ThreeK,
|
||||
/// Models: Nano Banana Pro
|
||||
FourK,
|
||||
|
||||
/// Used by Nano Banana 2 (and others)
|
||||
HalfK,
|
||||
|
||||
/// Used by the Seedance family (and others)
|
||||
FourEightyP,
|
||||
|
||||
/// Used by the Seedance family (and others)
|
||||
SevenTwentyP,
|
||||
|
||||
/// Used by the Seedance family (and others)
|
||||
TenEightyP,
|
||||
}
|
||||
|
||||
+5
@@ -8,5 +8,10 @@ pub fn resolution_to_artcraft_nano_banana_pro(resolution: CommonResolution) -> N
|
||||
// NB: ThreeK doesn't exist in Nano Banana Pro, use FourK as nearest higher resolution
|
||||
CommonResolution::ThreeK => NanoBananaProMultiFunctionImageGenImageResolution::FourK,
|
||||
CommonResolution::FourK => NanoBananaProMultiFunctionImageGenImageResolution::FourK,
|
||||
// Fall back to nearest supported resolution
|
||||
CommonResolution::HalfK => NanoBananaProMultiFunctionImageGenImageResolution::OneK,
|
||||
CommonResolution::FourEightyP => NanoBananaProMultiFunctionImageGenImageResolution::OneK,
|
||||
CommonResolution::SevenTwentyP => NanoBananaProMultiFunctionImageGenImageResolution::OneK,
|
||||
CommonResolution::TenEightyP => NanoBananaProMultiFunctionImageGenImageResolution::OneK,
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -144,5 +144,9 @@ fn convert_desktop_resolution(res: CommonResolution2) -> RouterCommonResolution
|
||||
CommonResolution2::TwoK => RouterCommonResolution::TwoK,
|
||||
CommonResolution2::ThreeK => RouterCommonResolution::ThreeK,
|
||||
CommonResolution2::FourK => RouterCommonResolution::FourK,
|
||||
CommonResolution2::HalfK => RouterCommonResolution::HalfK,
|
||||
CommonResolution2::FourEightyP => RouterCommonResolution::FourEightyP,
|
||||
CommonResolution2::SevenTwentyP => RouterCommonResolution::SevenTwentyP,
|
||||
CommonResolution2::TenEightyP => RouterCommonResolution::TenEightyP,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::error::enum_error::EnumError;
|
||||
|
||||
/// Maximum serialized string length for database storage.
|
||||
pub const MAX_LENGTH: usize = 16;
|
||||
|
||||
/// Common quality levels for generation.
|
||||
///
|
||||
/// NB: Keep the max serialized length to 16 characters.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CommonQuality {
|
||||
High,
|
||||
Medium,
|
||||
Low,
|
||||
}
|
||||
|
||||
impl_enum_display_and_debug_using_to_str!(CommonQuality);
|
||||
impl_mysql_enum_coders!(CommonQuality);
|
||||
impl_mysql_from_row!(CommonQuality);
|
||||
|
||||
impl CommonQuality {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::High => "high",
|
||||
Self::Medium => "medium",
|
||||
Self::Low => "low",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, EnumError> {
|
||||
match value {
|
||||
"high" => Ok(Self::High),
|
||||
"medium" => Ok(Self::Medium),
|
||||
"low" => Ok(Self::Low),
|
||||
_ => Err(EnumError::CouldNotConvertFromString(value.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
BTreeSet::from([
|
||||
Self::High,
|
||||
Self::Medium,
|
||||
Self::Low,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::common::generation::common_quality::CommonQuality;
|
||||
use crate::common::generation::common_quality::MAX_LENGTH;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
use crate::error::enum_error::EnumError;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(CommonQuality::High, "high");
|
||||
assert_serialization(CommonQuality::Medium, "medium");
|
||||
assert_serialization(CommonQuality::Low, "low");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(CommonQuality::High.to_str(), "high");
|
||||
assert_eq!(CommonQuality::Medium.to_str(), "medium");
|
||||
assert_eq!(CommonQuality::Low.to_str(), "low");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(CommonQuality::from_str("high").unwrap(), CommonQuality::High);
|
||||
assert_eq!(CommonQuality::from_str("medium").unwrap(), CommonQuality::Medium);
|
||||
assert_eq!(CommonQuality::from_str("low").unwrap(), CommonQuality::Low);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str_err() {
|
||||
let result = CommonQuality::from_str("invalid");
|
||||
assert!(result.is_err());
|
||||
if let Err(EnumError::CouldNotConvertFromString(value)) = result {
|
||||
assert_eq!(value, "invalid");
|
||||
} else {
|
||||
panic!("Expected EnumError::CouldNotConvertFromString");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = CommonQuality::all_variants();
|
||||
assert_eq!(variants.len(), 3);
|
||||
assert_eq!(variants.pop_first(), Some(CommonQuality::High));
|
||||
assert_eq!(variants.pop_first(), Some(CommonQuality::Medium));
|
||||
assert_eq!(variants.pop_first(), Some(CommonQuality::Low));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(CommonQuality::all_variants().len(), CommonQuality::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in CommonQuality::all_variants() {
|
||||
assert_eq!(variant, CommonQuality::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, CommonQuality::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, CommonQuality::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
for variant in CommonQuality::all_variants() {
|
||||
let serialized = variant.to_str();
|
||||
assert!(serialized.len() > 0, "variant {:?} is too short", variant);
|
||||
assert!(serialized.len() <= MAX_LENGTH, "variant {:?} is too long via to_str()", variant);
|
||||
}
|
||||
for variant in CommonQuality::all_variants() {
|
||||
let json = serde_json::to_string(&variant).unwrap().replace('"', "");
|
||||
assert!(json.len() <= MAX_LENGTH, "variant {:?} is too long via JSON: {:?}", variant, json);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_names_must_not_contain_dots() {
|
||||
for variant in CommonQuality::all_variants() {
|
||||
let to_str_value = variant.to_str();
|
||||
assert!(!to_str_value.contains('.'), "to_str() for {:?} contains a dot: {:?}", variant, to_str_value);
|
||||
|
||||
let json_value = serde_json::to_string(&variant).unwrap().replace('"', "");
|
||||
assert!(!json_value.contains('.'), "JSON serialization for {:?} contains a dot: {:?}", variant, json_value);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_names_must_only_contain_lowercase_alphanumeric_and_underscore() {
|
||||
let valid_pattern = regex::Regex::new(r"^[a-z0-9_]+$").unwrap();
|
||||
|
||||
for variant in CommonQuality::all_variants() {
|
||||
let to_str_value = variant.to_str();
|
||||
assert!(valid_pattern.is_match(to_str_value),
|
||||
"to_str() for {:?} contains invalid characters: {:?} (only a-z, 0-9, _ allowed)", variant, to_str_value);
|
||||
|
||||
let json_value = serde_json::to_string(&variant).unwrap().replace('"', "");
|
||||
assert!(valid_pattern.is_match(&json_value),
|
||||
"JSON serialization for {:?} contains invalid characters: {:?} (only a-z, 0-9, _ allowed)", variant, json_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,17 @@ pub enum CommonResolution {
|
||||
ThreeK,
|
||||
FourK,
|
||||
|
||||
// TODO: Add 480p(?), 720p(?), 1080p, etc. as there are some models that use these
|
||||
/// Used by Nano Banana 2 (and others)
|
||||
HalfK,
|
||||
|
||||
/// Used by the Seedance family (and others)
|
||||
FourEightyP,
|
||||
|
||||
/// Used by the Seedance family (and others)
|
||||
SevenTwentyP,
|
||||
|
||||
/// Used by the Seedance family (and others)
|
||||
TenEightyP,
|
||||
}
|
||||
|
||||
impl_enum_display_and_debug_using_to_str!(CommonResolution);
|
||||
@@ -37,6 +47,10 @@ impl CommonResolution {
|
||||
Self::TwoK => "two_k",
|
||||
Self::ThreeK => "three_k",
|
||||
Self::FourK => "four_k",
|
||||
Self::HalfK => "half_k",
|
||||
Self::FourEightyP => "four_eighty_p",
|
||||
Self::SevenTwentyP => "seven_twenty_p",
|
||||
Self::TenEightyP => "ten_eighty_p",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +60,10 @@ impl CommonResolution {
|
||||
"two_k" => Ok(Self::TwoK),
|
||||
"three_k" => Ok(Self::ThreeK),
|
||||
"four_k" => Ok(Self::FourK),
|
||||
"half_k" => Ok(Self::HalfK),
|
||||
"four_eighty_p" => Ok(Self::FourEightyP),
|
||||
"seven_twenty_p" => Ok(Self::SevenTwentyP),
|
||||
"ten_eighty_p" => Ok(Self::TenEightyP),
|
||||
_ => Err(EnumError::CouldNotConvertFromString(value.to_string())),
|
||||
}
|
||||
}
|
||||
@@ -56,6 +74,10 @@ impl CommonResolution {
|
||||
Self::TwoK,
|
||||
Self::ThreeK,
|
||||
Self::FourK,
|
||||
Self::HalfK,
|
||||
Self::FourEightyP,
|
||||
Self::SevenTwentyP,
|
||||
Self::TenEightyP,
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -76,6 +98,10 @@ mod tests {
|
||||
assert_serialization(CommonResolution::TwoK, "two_k");
|
||||
assert_serialization(CommonResolution::ThreeK, "three_k");
|
||||
assert_serialization(CommonResolution::FourK, "four_k");
|
||||
assert_serialization(CommonResolution::HalfK, "half_k");
|
||||
assert_serialization(CommonResolution::FourEightyP, "four_eighty_p");
|
||||
assert_serialization(CommonResolution::SevenTwentyP, "seven_twenty_p");
|
||||
assert_serialization(CommonResolution::TenEightyP, "ten_eighty_p");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -84,6 +110,10 @@ mod tests {
|
||||
assert_eq!(CommonResolution::TwoK.to_str(), "two_k");
|
||||
assert_eq!(CommonResolution::ThreeK.to_str(), "three_k");
|
||||
assert_eq!(CommonResolution::FourK.to_str(), "four_k");
|
||||
assert_eq!(CommonResolution::HalfK.to_str(), "half_k");
|
||||
assert_eq!(CommonResolution::FourEightyP.to_str(), "four_eighty_p");
|
||||
assert_eq!(CommonResolution::SevenTwentyP.to_str(), "seven_twenty_p");
|
||||
assert_eq!(CommonResolution::TenEightyP.to_str(), "ten_eighty_p");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -92,6 +122,10 @@ mod tests {
|
||||
assert_eq!(CommonResolution::from_str("two_k").unwrap(), CommonResolution::TwoK);
|
||||
assert_eq!(CommonResolution::from_str("three_k").unwrap(), CommonResolution::ThreeK);
|
||||
assert_eq!(CommonResolution::from_str("four_k").unwrap(), CommonResolution::FourK);
|
||||
assert_eq!(CommonResolution::from_str("half_k").unwrap(), CommonResolution::HalfK);
|
||||
assert_eq!(CommonResolution::from_str("four_eighty_p").unwrap(), CommonResolution::FourEightyP);
|
||||
assert_eq!(CommonResolution::from_str("seven_twenty_p").unwrap(), CommonResolution::SevenTwentyP);
|
||||
assert_eq!(CommonResolution::from_str("ten_eighty_p").unwrap(), CommonResolution::TenEightyP);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -108,11 +142,15 @@ mod tests {
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = CommonResolution::all_variants();
|
||||
assert_eq!(variants.len(), 4);
|
||||
assert_eq!(variants.len(), 8);
|
||||
assert_eq!(variants.pop_first(), Some(CommonResolution::OneK));
|
||||
assert_eq!(variants.pop_first(), Some(CommonResolution::TwoK));
|
||||
assert_eq!(variants.pop_first(), Some(CommonResolution::ThreeK));
|
||||
assert_eq!(variants.pop_first(), Some(CommonResolution::FourK));
|
||||
assert_eq!(variants.pop_first(), Some(CommonResolution::HalfK));
|
||||
assert_eq!(variants.pop_first(), Some(CommonResolution::FourEightyP));
|
||||
assert_eq!(variants.pop_first(), Some(CommonResolution::SevenTwentyP));
|
||||
assert_eq!(variants.pop_first(), Some(CommonResolution::TenEightyP));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod common_aspect_ratio;
|
||||
pub mod common_generation_mode;
|
||||
pub mod common_image_model;
|
||||
pub mod common_quality;
|
||||
pub mod common_model_class;
|
||||
pub mod common_model_type;
|
||||
pub mod common_resolution;
|
||||
|
||||
+4
@@ -168,5 +168,9 @@ fn map_resolution(res: CommonResolution) -> RouterResolution {
|
||||
CommonResolution::TwoK => RouterResolution::TwoK,
|
||||
CommonResolution::ThreeK => RouterResolution::ThreeK,
|
||||
CommonResolution::FourK => RouterResolution::FourK,
|
||||
CommonResolution::HalfK => RouterResolution::HalfK,
|
||||
CommonResolution::FourEightyP => RouterResolution::FourEightyP,
|
||||
CommonResolution::SevenTwentyP => RouterResolution::SevenTwentyP,
|
||||
CommonResolution::TenEightyP => RouterResolution::TenEightyP,
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -178,5 +178,9 @@ fn map_resolution(res: CommonResolution) -> RouterResolution {
|
||||
CommonResolution::TwoK => RouterResolution::TwoK,
|
||||
CommonResolution::ThreeK => RouterResolution::ThreeK,
|
||||
CommonResolution::FourK => RouterResolution::FourK,
|
||||
CommonResolution::HalfK => RouterResolution::HalfK,
|
||||
CommonResolution::FourEightyP => RouterResolution::FourEightyP,
|
||||
CommonResolution::SevenTwentyP => RouterResolution::SevenTwentyP,
|
||||
CommonResolution::TenEightyP => RouterResolution::TenEightyP,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user