From 8e67654b9d0613730ff233c171fdbfe2ceec4175 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 25 Jan 2026 19:05:20 -0500 Subject: [PATCH] nano banana text-to-image pane fixes (#1010) fix reference images, resolution controls, etc. --- .../aspect_ratio/common_aspect_ratio.rs | 4 +- .../artcraft/src/core/api_adapters/mod.rs | 3 +- .../resolution/common_resolution.rs | 17 +++ .../api_adapters/resolution/convert/mod.rs | 1 + .../resolution_to_artcraft_nano_banana_pro.rs | 12 ++ .../src/core/api_adapters/resolution/mod.rs | 2 + ...le_artcraft_gpt_image_1p5_text_to_image.rs | 3 +- ..._artcraft_nano_banana_pro_text_to_image.rs | 29 ++-- .../enqueue_text_to_image_command.rs | 20 ++- ...na_pro_multi_function_image_gen_handler.rs | 6 +- .../promptbox/src/lib/PromptBoxImage.tsx | 18 ++- .../src/lib/common/ResolutionPicker.tsx | 126 ++++++++++++++++++ frontend/libs/model-list/src/index.ts | 1 + .../model-list/src/lib/classes/ImageModel.ts | 19 +++ .../classes/properties/CommonResolution.ts | 9 ++ .../model-list/src/lib/lists/ImageModels.ts | 6 + .../src/lib/enqueue/EnqueueTextToImage.ts | 24 +++- frontend/package-lock.json | 23 ++++ 18 files changed, 293 insertions(+), 30 deletions(-) create mode 100644 crates/desktop/artcraft/src/core/api_adapters/resolution/common_resolution.rs create mode 100644 crates/desktop/artcraft/src/core/api_adapters/resolution/convert/mod.rs create mode 100644 crates/desktop/artcraft/src/core/api_adapters/resolution/convert/resolution_to_artcraft_nano_banana_pro.rs create mode 100644 crates/desktop/artcraft/src/core/api_adapters/resolution/mod.rs create mode 100644 frontend/libs/components/promptbox/src/lib/common/ResolutionPicker.tsx create mode 100644 frontend/libs/model-list/src/lib/classes/properties/CommonResolution.ts diff --git a/crates/desktop/artcraft/src/core/api_adapters/aspect_ratio/common_aspect_ratio.rs b/crates/desktop/artcraft/src/core/api_adapters/aspect_ratio/common_aspect_ratio.rs index 8a7d1365e3..c16d63e159 100644 --- a/crates/desktop/artcraft/src/core/api_adapters/aspect_ratio/common_aspect_ratio.rs +++ b/crates/desktop/artcraft/src/core/api_adapters/aspect_ratio/common_aspect_ratio.rs @@ -1,8 +1,8 @@ use serde_derive::{Deserialize, Serialize}; -/// This is a comprehensive list of common aspect ratios. +/// This is a comprehensive list of common aspect ratios you can specify when enqueuing a generation. /// Not every model will support every aspect ratio. -/// In the case a model doesn't support the aspect ratio, pick the nearest option. +/// In the case a model doesn't support the aspect ratio, gracefully pick the nearest option. #[derive(Copy, Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum CommonAspectRatio { diff --git a/crates/desktop/artcraft/src/core/api_adapters/mod.rs b/crates/desktop/artcraft/src/core/api_adapters/mod.rs index 02401adae4..9bc267ec50 100644 --- a/crates/desktop/artcraft/src/core/api_adapters/mod.rs +++ b/crates/desktop/artcraft/src/core/api_adapters/mod.rs @@ -1 +1,2 @@ -pub mod aspect_ratio; \ No newline at end of file +pub mod aspect_ratio; +pub mod resolution; \ No newline at end of file diff --git a/crates/desktop/artcraft/src/core/api_adapters/resolution/common_resolution.rs b/crates/desktop/artcraft/src/core/api_adapters/resolution/common_resolution.rs new file mode 100644 index 0000000000..f262faadb8 --- /dev/null +++ b/crates/desktop/artcraft/src/core/api_adapters/resolution/common_resolution.rs @@ -0,0 +1,17 @@ +use serde_derive::{Deserialize, Serialize}; + +/// This is a comprehensive list of common resolutions you can specify when enqueuing a generation. +/// Not every model will support every resolution +/// In the case a model doesn't support the resolution, gracefully pick the nearest option. +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum CommonResolution { + /// Models: Nano Banana Pro + OneK, + /// Models: Nano Banana Pro + TwoK, + /// Models: (None) + ThreeK, + /// Models: Nano Banana Pro + FourK, +} diff --git a/crates/desktop/artcraft/src/core/api_adapters/resolution/convert/mod.rs b/crates/desktop/artcraft/src/core/api_adapters/resolution/convert/mod.rs new file mode 100644 index 0000000000..8d8736d597 --- /dev/null +++ b/crates/desktop/artcraft/src/core/api_adapters/resolution/convert/mod.rs @@ -0,0 +1 @@ +pub mod resolution_to_artcraft_nano_banana_pro; \ No newline at end of file diff --git a/crates/desktop/artcraft/src/core/api_adapters/resolution/convert/resolution_to_artcraft_nano_banana_pro.rs b/crates/desktop/artcraft/src/core/api_adapters/resolution/convert/resolution_to_artcraft_nano_banana_pro.rs new file mode 100644 index 0000000000..a7668aed7a --- /dev/null +++ b/crates/desktop/artcraft/src/core/api_adapters/resolution/convert/resolution_to_artcraft_nano_banana_pro.rs @@ -0,0 +1,12 @@ +use crate::core::api_adapters::resolution::common_resolution::CommonResolution; +use artcraft_api_defs::generate::image::multi_function::nano_banana_pro_multi_function_image_gen::NanoBananaProMultiFunctionImageGenImageResolution; + +pub fn resolution_to_artcraft_nano_banana_pro(resolution: CommonResolution) -> NanoBananaProMultiFunctionImageGenImageResolution { + match resolution { + CommonResolution::OneK => NanoBananaProMultiFunctionImageGenImageResolution::OneK, + CommonResolution::TwoK => NanoBananaProMultiFunctionImageGenImageResolution::TwoK, + // NB: ThreeK doesn't exist in Nano Banana Pro, use FourK as nearest higher resolution + CommonResolution::ThreeK => NanoBananaProMultiFunctionImageGenImageResolution::FourK, + CommonResolution::FourK => NanoBananaProMultiFunctionImageGenImageResolution::FourK, + } +} diff --git a/crates/desktop/artcraft/src/core/api_adapters/resolution/mod.rs b/crates/desktop/artcraft/src/core/api_adapters/resolution/mod.rs new file mode 100644 index 0000000000..f1197a3d7b --- /dev/null +++ b/crates/desktop/artcraft/src/core/api_adapters/resolution/mod.rs @@ -0,0 +1,2 @@ +pub mod common_resolution; +pub mod convert; \ No newline at end of file diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_artcraft_gpt_image_1p5_text_to_image.rs b/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_artcraft_gpt_image_1p5_text_to_image.rs index 91d508b77a..84cfef88de 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_artcraft_gpt_image_1p5_text_to_image.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_artcraft_gpt_image_1p5_text_to_image.rs @@ -62,8 +62,7 @@ pub async fn handle_artcraft_gpt_image_1p5_text_to_image( prompt: request.prompt.clone(), image_size: aspect_ratio, num_images, - // Not provided for text-to-image - image_media_tokens: None, + image_media_tokens: request.image_media_tokens.clone(), mask_image_token: None, input_fidelity: None, // Not provided diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_artcraft_nano_banana_pro_text_to_image.rs b/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_artcraft_nano_banana_pro_text_to_image.rs index ce603276c2..aa72790492 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_artcraft_nano_banana_pro_text_to_image.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_artcraft_nano_banana_pro_text_to_image.rs @@ -1,5 +1,7 @@ use crate::core::api_adapters::aspect_ratio::common_aspect_ratio::CommonAspectRatio; use crate::core::api_adapters::aspect_ratio::convert::aspect_ratio_to_artcraft_nano_banana_pro::aspect_ratio_to_artcraft_nano_banana_pro; +use crate::core::api_adapters::resolution::common_resolution::CommonResolution; +use crate::core::api_adapters::resolution::convert::resolution_to_artcraft_nano_banana_pro::resolution_to_artcraft_nano_banana_pro; use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError, MissingCredentialsReason, ProviderFailureReason}; use crate::core::commands::enqueue::image_edit::enqueue_edit_image_command::{EditImageQuality, EditImageResolution, EditImageSize}; use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; @@ -61,18 +63,12 @@ pub async fn handle_artcraft_nano_banana_pro_text_to_image( }; let aspect_ratio = get_aspect_ratio(request); - - let resolution = request.image_resolution - .map(|image_resolution| match image_resolution { - TextToImageResolution::OneK => NanoBananaProMultiFunctionImageGenImageResolution::OneK, - TextToImageResolution::TwoK => NanoBananaProMultiFunctionImageGenImageResolution::TwoK, - TextToImageResolution::FourK => NanoBananaProMultiFunctionImageGenImageResolution::FourK, - }); + let resolution = get_resolution(request); let request = NanoBananaProMultiFunctionImageGenRequest { uuid_idempotency_token, prompt: request.prompt.clone(), - image_media_tokens: None, + image_media_tokens: request.image_media_tokens.clone(), num_images, resolution, aspect_ratio, @@ -126,3 +122,20 @@ fn get_aspect_ratio(request: &EnqueueTextToImageRequest) -> Option Option { + if let Some(common_resolution) = request.common_resolution { + return Some(resolution_to_artcraft_nano_banana_pro(common_resolution)); + } + + if let Some(resolution) = request.image_resolution { + // Deprecated resolution + return Some(match resolution { + TextToImageResolution::OneK => NanoBananaProMultiFunctionImageGenImageResolution::OneK, + TextToImageResolution::TwoK => NanoBananaProMultiFunctionImageGenImageResolution::TwoK, + TextToImageResolution::FourK => NanoBananaProMultiFunctionImageGenImageResolution::FourK, + }) + } + + None +} diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/enqueue_text_to_image_command.rs b/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/enqueue_text_to_image_command.rs index 7f19dc7ade..056de965bb 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/enqueue_text_to_image_command.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/enqueue_text_to_image_command.rs @@ -1,3 +1,5 @@ +use crate::core::api_adapters::aspect_ratio::common_aspect_ratio::CommonAspectRatio; +use crate::core::api_adapters::resolution::common_resolution::CommonResolution; use crate::core::commands::enqueue::common::notify_frontend_of_errors::notify_frontend_of_errors; use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError, MissingCredentialsReason}; use crate::core::commands::enqueue::image_edit::image_edit_models::image_edit_model_to_model_type; @@ -16,6 +18,8 @@ use crate::core::events::generation_events::common::{GenerationAction, Generatio use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent; use crate::core::events::sendable_event_trait::SendableEvent; use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; +use crate::core::state::artcraft_usage_tracker::artcraft_usage_tracker::ArtcraftUsageTracker; +use crate::core::state::artcraft_usage_tracker::artcraft_usage_type::{ArtcraftUsagePage, ArtcraftUsageType}; use crate::core::state::data_dir::app_data_root::AppDataRoot; use crate::core::state::provider_priority::{Provider, ProviderPriorityStore}; use crate::core::state::task_database::TaskDatabase; @@ -34,9 +38,6 @@ use serde::{Deserialize, Serialize}; use sqlite_tasks::queries::create_task::{create_task, CreateTaskArgs}; use tauri::{AppHandle, State}; use tokens::tokens::media_files::MediaFileToken; -use crate::core::api_adapters::aspect_ratio::common_aspect_ratio::CommonAspectRatio; -use crate::core::state::artcraft_usage_tracker::artcraft_usage_tracker::ArtcraftUsageTracker; -use crate::core::state::artcraft_usage_tracker::artcraft_usage_type::{ArtcraftUsagePage, ArtcraftUsageType}; /// This is used in the Tauri command bridge. /// Don't change the serializations without coordinating with the frontend. @@ -88,15 +89,20 @@ pub struct EnqueueTextToImageRequest { /// Text prompt for the image generation. Required. pub prompt: Option, - /// Aspect ratio. - #[deprecated(note="use common_aspect_ratio")] - pub aspect_ratio: Option, - /// New field for aspect ratio. /// Not all models support each of these aspect ratios, but we can choose or interpolate sensibly. pub common_aspect_ratio: Option, + /// New field for resolution. + /// Not all models support each of these resolutions, but we can choose or interpolate sensibly. + pub common_resolution: Option, + /// Aspect ratio. + #[deprecated(note="use common_aspect_ratio")] + pub aspect_ratio: Option, + + /// Aspect ratio. + #[deprecated(note="use common_resolution")] pub image_resolution: Option, /// The number of images to generate. diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/image/multi_function/nano_banana_pro_multi_function_image_gen_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/image/multi_function/nano_banana_pro_multi_function_image_gen_handler.rs index 75dfb501a0..5ea864c1ed 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/image/multi_function/nano_banana_pro_multi_function_image_gen_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/image/multi_function/nano_banana_pro_multi_function_image_gen_handler.rs @@ -153,7 +153,7 @@ pub async fn nano_banana_pro_multi_function_image_gen_handler( None => EnqueueNanoBananaProEditImageNumImages::One, // Default to One }; - let resolution = match request.resolution { + let mut resolution = match request.resolution { Some(NanoBananaProMultiFunctionImageGenImageResolution::OneK) => EnqueueNanoBananaProEditImageResolution::OneK, Some(NanoBananaProMultiFunctionImageGenImageResolution::TwoK) => EnqueueNanoBananaProEditImageResolution::TwoK, Some(NanoBananaProMultiFunctionImageGenImageResolution::FourK) => EnqueueNanoBananaProEditImageResolution::FourK, @@ -177,6 +177,7 @@ pub async fn nano_banana_pro_multi_function_image_gen_handler( if downgrade_for_free_user { num_images = EnqueueNanoBananaProEditImageNumImages::One; + resolution = EnqueueNanoBananaProEditImageResolution::OneK; } let args = EnqueueNanoBananaProEditImageArgs { @@ -207,7 +208,7 @@ pub async fn nano_banana_pro_multi_function_image_gen_handler( None => EnqueueNanoBananaProTextToImageNumImages::One, // Default to One }; - let resolution = match request.resolution { + let mut resolution = match request.resolution { Some(NanoBananaProMultiFunctionImageGenImageResolution::OneK) => EnqueueNanoBananaProTextToImageResolution::OneK, Some(NanoBananaProMultiFunctionImageGenImageResolution::TwoK) => EnqueueNanoBananaProTextToImageResolution::TwoK, Some(NanoBananaProMultiFunctionImageGenImageResolution::FourK) => EnqueueNanoBananaProTextToImageResolution::FourK, @@ -231,6 +232,7 @@ pub async fn nano_banana_pro_multi_function_image_gen_handler( if downgrade_for_free_user { num_images = EnqueueNanoBananaProTextToImageNumImages::One; + resolution = EnqueueNanoBananaProTextToImageResolution::OneK; } let args = EnqueueNanoBananaProTextToImageArgs { diff --git a/frontend/libs/components/promptbox/src/lib/PromptBoxImage.tsx b/frontend/libs/components/promptbox/src/lib/PromptBoxImage.tsx index 96621a1f2b..8109412ca4 100644 --- a/frontend/libs/components/promptbox/src/lib/PromptBoxImage.tsx +++ b/frontend/libs/components/promptbox/src/lib/PromptBoxImage.tsx @@ -35,6 +35,8 @@ import { ImagePromptRow } from "./ImagePromptRow"; import { GenerationProvider } from "@storyteller/api-enums"; import { AspectRatioPicker } from "./common/AspectRatioPicker"; import { GenerationCountPicker } from "./common/GenerationCountPicker"; +import { ResolutionPicker } from "./common/ResolutionPicker"; +import { CommonResolution } from "@storyteller/model-list"; interface PromptBoxImageProps { useJobContext: () => JobContextType; @@ -114,6 +116,9 @@ export const PromptBoxImage = ({ // New aspect ratio state will begin to phase out old aspect ratio const [commonAspectRatio, setCommonAspectRatio] = useState(undefined); + // New resolution state will begin to phase out old resolution + const [commonResolution, setCommonResolution] = useState(undefined); + useEffect(() => { onImageRowVisibilityChange?.(isImageRowVisible); }, [isImageRowVisible, onImageRowVisibilityChange]); @@ -280,6 +285,10 @@ export const PromptBoxImage = ({ request.common_aspect_ratio = commonAspectRatio; } + if (selectedModel?.supportsNewResolution()) { + request.common_resolution = commonResolution; + } + if ( selectedModel?.canUseImagePrompt && !!referenceImages && @@ -472,7 +481,14 @@ export const PromptBoxImage = ({ /> )} - {selectedModel?.canChangeResolution && ( + {selectedModel?.supportsNewResolution() && ( + + )} + {selectedModel?.canChangeResolution && !selectedModel?.supportsNewResolution() && ( void; + //model: ImageModel | VideoModel +} + +/** + * Stateless component. + * + * Picker for "common aspect ratios", the new data structure Tauri accepts for + * all image and video models (Note: this is not fully rolled out yet. Some/most + * models may still use the old format.) + * + * @param model - currently selected model + * @param currentAspectRatio - currently selected aspect ratio + * @param handleCommonResolutionSelect - callback when a resolution is selected + */ +export const ResolutionPicker = ({ + model, + currentResolution, + handleCommonResolutionSelect, +}: ResolutionPickerProps) => { + + const useResolution = currentResolution ?? model.defaultResolution ?? undefined; + + console.log("resolution - currentResolution:", currentResolution); + console.log("resolution - useResolution:", useResolution); + + const getCurrentResolutionIcon = () : IconDefinition => { + if (!useResolution) { + return faSquare; + } + return getResolutionIcon(useResolution); + } + + const handleSelectAdapter = (item: PopoverItem) => { + const resolution = popOverLabelToResolution(item.label, model); + handleCommonResolutionSelect(resolution); + } + + let resolutionList : PopoverItem[] = []; + + model.resolutions?.forEach((resolution: CommonResolution) => { + resolutionList.push({ + label: getResolutionTextLabel(resolution), + selected: useResolution === resolution, + description: `foo ${resolution}`, + icon: , + }); + }); + + return ( + <> + + + } + /> + + + ) +} + + +const getResolutionIcon = (resolution: CommonResolution) : IconDefinition => { + switch (resolution) { + case CommonResolution.OneK: + return faStandardDefinition; + case CommonResolution.TwoK: + return faHighDefinition; + case CommonResolution.FourK: + return faHighDefinition; // TODO: Upgrade Font Awesome to include 4K icon + default: + console.error("Unknown resolution in icon mapping:", resolution); + return faStandardDefinition; // Fail open-ish + } +} + +const getResolutionTextLabel = (resolution: CommonResolution) : string => { + switch (resolution) { + case CommonResolution.OneK: + return "1K"; + case CommonResolution.TwoK: + return "2K"; + case CommonResolution.FourK: + return "4K"; + default: + console.error("Unknown resolution:", resolution); + return "1K"; // Fail open-ish + } +} + +// Note: We only need this to deal with turning PopOverItems back into typesafe aspect ratios +const popOverLabelToResolution = (label: string, model: ImageModel): CommonResolution => { + switch (label) { + case "1K": return CommonResolution.OneK; + case "2K": return CommonResolution.TwoK; + case "4K": return CommonResolution.FourK; + } + console.error("Unknown resolution label:", label, "for model:", model.id); + // If we can't find it, return the model's default resolution or 1K as fallback + return model.defaultResolution || CommonResolution.OneK; +} diff --git a/frontend/libs/model-list/src/index.ts b/frontend/libs/model-list/src/index.ts index c5bac936dd..5b78e0076b 100644 --- a/frontend/libs/model-list/src/index.ts +++ b/frontend/libs/model-list/src/index.ts @@ -2,6 +2,7 @@ export * from "./lib/classes/ImageModel.js"; export * from "./lib/classes/Model.js"; export * from "./lib/classes/VideoModel.js"; export * from "./lib/classes/properties/CommonAspectRatio.js"; +export * from "./lib/classes/properties/CommonResolution.js"; export * from "./lib/classes/metadata/ModelCreator.js"; export * from "./lib/classes/metadata/ModelCreatorIcons.js"; export * from "./lib/classes/metadata/ModelMapping.js"; diff --git a/frontend/libs/model-list/src/lib/classes/ImageModel.ts b/frontend/libs/model-list/src/lib/classes/ImageModel.ts index ca98adbf2b..7da7ff921c 100644 --- a/frontend/libs/model-list/src/lib/classes/ImageModel.ts +++ b/frontend/libs/model-list/src/lib/classes/ImageModel.ts @@ -4,6 +4,7 @@ import { ModelCategory } from "../legacy/ModelConfig.js"; import { ModelTag } from "./metadata/ModelTag.js"; import { GenerationProvider } from "@storyteller/api-enums"; import { CommonAspectRatio } from "./properties/CommonAspectRatio.js"; +import { CommonResolution } from "./properties/CommonResolution.js"; export class ImageModel extends Model { // Typescript type discriminator property @@ -51,10 +52,16 @@ export class ImageModel extends Model { // (This is a new field that will take time to roll out and replace the old aspect ratios) readonly aspectRatios: CommonAspectRatio[]; + readonly resolutions: CommonResolution[]; + // Aspect ratio to use as default when nothing is selected. // Otherwise, use `aspectRatios[0]` as default. readonly defaultAspectRatio?: CommonAspectRatio; + // Resolution to use as default when nothing is selected. + // Otherwise, use `resolutions[0]` as default. + readonly defaultResolution?: CommonResolution; + constructor(args: { id: string; tauriId: string; @@ -79,7 +86,9 @@ export class ImageModel extends Model { progressBarTime?: number; providers?: GenerationProvider[]; aspectRatios?: CommonAspectRatio[]; + resolutions?: CommonResolution[]; defaultAspectRatio?: CommonAspectRatio; + defaultResolution?: CommonResolution; }) { if (args.maxGenerationCount < 1) { throw new Error("maxGenerationCount must be at least 1"); @@ -105,7 +114,9 @@ export class ImageModel extends Model { this.canChangeResolution = args.canChangeResolution ?? false; this.canChangeAspectRatio = args.canChangeAspectRatio ?? false; this.aspectRatios = args.aspectRatios ?? []; + this.resolutions = args.resolutions ?? []; this.defaultAspectRatio = args.defaultAspectRatio ?? (args.aspectRatios && args.aspectRatios.length > 0 ? args.aspectRatios[0] : undefined); + this.defaultResolution = args.defaultResolution ?? (args.resolutions && args.resolutions.length > 0 ? args.resolutions[0] : undefined); } // If the model is a "Nano Banana"-type model, we may want to enable certain features. @@ -131,6 +142,14 @@ export class ImageModel extends Model { && this.aspectRatios.length > 0; } + // Rolling out new resolution controls to models. + // If we have them set on the model, we can use the new UI controls. + supportsNewResolution(): boolean { + return this.canChangeResolution + && this.resolutions + && this.resolutions.length > 0; + } + // Return whether the count of generations is valid for this model isValidGenerationCount(count: number): boolean { if (this.predefinedGenerationCounts) { diff --git a/frontend/libs/model-list/src/lib/classes/properties/CommonResolution.ts b/frontend/libs/model-list/src/lib/classes/properties/CommonResolution.ts new file mode 100644 index 0000000000..a7054b2325 --- /dev/null +++ b/frontend/libs/model-list/src/lib/classes/properties/CommonResolution.ts @@ -0,0 +1,9 @@ + +/// Common aspect ratio Tauri API +/// Not all models have each of these aspect ratios, +/// but Tauri will interpolate if a mistake is sent. +export enum CommonResolution { + OneK = "one_k", + TwoK = "two_k", + FourK = "four_k", +} \ No newline at end of file diff --git a/frontend/libs/model-list/src/lib/lists/ImageModels.ts b/frontend/libs/model-list/src/lib/lists/ImageModels.ts index 2ea86bde86..a2600cee6b 100644 --- a/frontend/libs/model-list/src/lib/lists/ImageModels.ts +++ b/frontend/libs/model-list/src/lib/lists/ImageModels.ts @@ -3,6 +3,7 @@ import { ImageModel } from "../classes/ImageModel.js"; import { ModelCreator } from "../classes/metadata/ModelCreator.js"; import { ModelTag } from "../classes/metadata/ModelTag.js"; import { CommonAspectRatio } from "../classes/properties/CommonAspectRatio.js"; +import { CommonResolution } from "../classes/properties/CommonResolution.js"; // TODO: Some of the model configs, such as generation counts, are authoritatively controlled in `legacy/Models.ts` @@ -224,6 +225,11 @@ export const IMAGE_MODELS: ImageModel[] = [ CommonAspectRatio.TallThreeByFour, CommonAspectRatio.TallTwoByThree, CommonAspectRatio.TallNineBySixteen, + ], + resolutions: [ + CommonResolution.OneK, + CommonResolution.TwoK, + CommonResolution.FourK, ] }), new ImageModel({ diff --git a/frontend/libs/tauri-api/src/lib/enqueue/EnqueueTextToImage.ts b/frontend/libs/tauri-api/src/lib/enqueue/EnqueueTextToImage.ts index 17b1d20d03..6361797cf1 100644 --- a/frontend/libs/tauri-api/src/lib/enqueue/EnqueueTextToImage.ts +++ b/frontend/libs/tauri-api/src/lib/enqueue/EnqueueTextToImage.ts @@ -2,6 +2,7 @@ import { invoke } from "@tauri-apps/api/core"; import { CommandResult } from "../common/CommandStatus"; import { CommonAspectRatio, Model } from "@storyteller/model-list"; import { GenerationProvider } from "@storyteller/api-enums"; +import { CommonResolution } from "@storyteller/model-list"; export enum EnqueueTextToImageErrorType { /// Caller didn't specify a model @@ -24,13 +25,17 @@ export interface EnqueueTextToImageRequest { // The text prompt. prompt?: string; + // This is the new aspect ratio. + common_aspect_ratio?: CommonAspectRatio; + + // This is the new aspect ratio. + common_resolution?: CommonResolution; + // TODO: This is deprecated and will be phased out. // The desired output aspect ratio. aspect_ratio?: EnqueueTextToImageSize; - // This is the new aspect ratio. - common_aspect_ratio?: CommonAspectRatio; - + // TODO: This is deprecated and will be phased out. // Image resolution. Support: Nano Banana Pro image_resolution?: EnqueueTextToImageResolution; @@ -59,6 +64,7 @@ interface EnqueueTextToImageRawRequest { prompt?: string; aspect_ratio?: EnqueueTextToImageSize; common_aspect_ratio?: CommonAspectRatio; + common_resolution?: CommonResolution; image_resolution?: EnqueueTextToImageResolution; number_images?: number; image_media_tokens?: string[]; @@ -127,14 +133,18 @@ export const EnqueueTextToImage = async (request: EnqueueTextToImageRequest) : P mutableRequest.provider = request.provider; } - if (!!request.aspect_ratio) { - mutableRequest.aspect_ratio = request.aspect_ratio; - } - if (!!request.common_aspect_ratio) { mutableRequest.common_aspect_ratio = request.common_aspect_ratio; } + if (!!request.common_resolution) { + mutableRequest.common_resolution = request.common_resolution; + } + + if (!!request.aspect_ratio) { + mutableRequest.aspect_ratio = request.aspect_ratio; + } + if (!!request.image_resolution) { mutableRequest.image_resolution = request.image_resolution; } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 11a1a13712..f3d62d6a83 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2895,6 +2895,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=12" } @@ -2912,6 +2913,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=12" } @@ -2929,6 +2931,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=12" } @@ -2946,6 +2949,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=12" } @@ -2963,6 +2967,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=12" } @@ -2980,6 +2985,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=12" } @@ -2997,6 +3003,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -3014,6 +3021,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -3031,6 +3039,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -3048,6 +3057,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -3065,6 +3075,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -3082,6 +3093,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -3099,6 +3111,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -3116,6 +3129,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -3133,6 +3147,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -3150,6 +3165,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -3167,6 +3183,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -3201,6 +3218,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -3235,6 +3253,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -3269,6 +3288,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=12" } @@ -3286,6 +3306,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=12" } @@ -3303,6 +3324,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=12" } @@ -3320,6 +3342,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=12" }