Compare commits

...
Author SHA1 Message Date
Brandon Thomas 15146f1f21 2d aspect ratio 2025-05-22 00:09:23 -04:00
Brandon Thomas 53fb8533fc aspect ratio switch 2025-05-21 23:49:24 -04:00
4 changed files with 69 additions and 13 deletions
@@ -42,7 +42,9 @@ const SORA_IMAGE_UPLOAD_TIMEOUT: Duration = Duration::from_millis(1000 * 30); //
const SORA_IMAGE_REMIX_TIMEOUT: Duration = Duration::from_millis(1000 * 30); // 30 seconds
#[derive(Deserialize)]
const DEFAULT_ASPECT_RATIO : SoraAspectRatio = SoraAspectRatio::Square;
#[derive(Deserialize, Debug)]
pub struct SoraImageRemixCommand {
/// Image media file; the engine or canvas snapshot (screenshot).
pub snapshot_media_token: MediaFileToken,
@@ -57,6 +59,17 @@ pub struct SoraImageRemixCommand {
pub maybe_additional_images: Option<Vec<MediaFileToken>>,
pub maybe_number_of_samples: Option<u32>,
/// Aspect ratio.
pub aspect_ratio: Option<SoraAspectRatio>,
}
#[derive(Deserialize, Debug, Copy, Clone)]
#[serde(rename_all = "snake_case")]
pub enum SoraAspectRatio {
Square,
Wide,
Tall,
}
#[derive(Serialize, Debug)]
@@ -74,7 +87,6 @@ pub enum SoraImageRemixErrorType {
SoraIsHavingProblems,
}
#[tauri::command]
pub async fn sora_image_remix_command(
app: AppHandle,
@@ -84,8 +96,8 @@ pub async fn sora_image_remix_command(
sora_task_queue: State<'_, SoraTaskQueue>,
) -> CommandResult<(), SoraImageRemixErrorType, ()> {
info!("image_generation_command called; scene media token: {:?}, additional images: {:?}",
request.snapshot_media_token, request.maybe_additional_images);
info!("image_generation_command called; scene media token: {:?}, additional images: {:?}, full request: {:?}",
&request.snapshot_media_token, &request.maybe_additional_images, &request);
// TODO(bt,2025-04-24): Better error messages to caller
@@ -240,6 +252,14 @@ pub async fn generate_image(
sora_media_tokens.push(response.id);
}
let aspect_ratio = request.aspect_ratio.unwrap_or(DEFAULT_ASPECT_RATIO);
let aspect_ratio = match aspect_ratio {
SoraAspectRatio::Square => ImageSize::Square,
SoraAspectRatio::Wide => ImageSize::Wide,
SoraAspectRatio::Tall => ImageSize::Tall,
};
info!("Calling image generation...");
// TODO(bt,2025-04-21): Download media tokens.
@@ -250,7 +270,7 @@ pub async fn generate_image(
image_remix_with_session_auto_renew(ImageRemixAutoRenewRequest {
prompt: request.prompt.to_string(),
num_images: NumImages::One,
image_size: ImageSize::Square,
image_size: aspect_ratio,
sora_media_tokens: sora_media_tokens.clone(),
credentials: &creds,
request_timeout: Some(SORA_IMAGE_REMIX_TIMEOUT),
@@ -1,5 +1,4 @@
import { useState, useRef, useEffect } from "react";
import { invoke } from "@tauri-apps/api/core";
import { useSignals } from "@preact/signals-react/runtime";
import { toast } from "@storyteller/ui-toaster";
import {
@@ -37,6 +36,7 @@ import {
GetAppPreferences,
SoraImageRemix,
SoraImageRemixErrorType,
SoraImageRemixAspectRatio,
} from "@storyteller/tauri-api";
import { SoundRegistry } from "@storyteller/soundboard";
@@ -291,12 +291,15 @@ export const PromptBox2D = ({
//console.log("Generate response:", generateResponse);
//toast.success("Please wait while we process your image.");
const aspectRatio = getCurrentSoraRemixAspectRatio();
const generateResponse = await SoraImageRemix({
snapshot_media_token: snapshotMediaToken.data,
disable_system_prompt: !useSystemPrompt,
prompt: prompt,
maybe_additional_images: referenceImages.map((image) => image.mediaToken),
maybe_number_of_samples: 1,
aspect_ratio: aspectRatio,
});
console.log("generateResponse", generateResponse);
@@ -448,6 +451,19 @@ export const PromptBox2D = ({
return iconElement.props.icon;
};
const getCurrentSoraRemixAspectRatio = (): SoraImageRemixAspectRatio => {
const selected = aspectRatioList.find((item) => item.selected);
switch (selected?.label) {
case "3:2":
return SoraImageRemixAspectRatio.Wide;
case "2:3":
return SoraImageRemixAspectRatio.Tall;
case "1:1":
default:
return SoraImageRemixAspectRatio.Square;
}
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
@@ -51,6 +51,7 @@ import {
CommandSuccessStatus,
GetAppPreferences,
SoraImageRemix,
SoraImageRemixAspectRatio,
SoraImageRemixErrorType,
} from "@storyteller/tauri-api";
@@ -415,6 +416,8 @@ export const PromptBox3D = ({
console.log("snapshotResult", snapshotResult);
const aspectRatio = getCurrentSoraRemixAspectRatio();
const generateResponse = await SoraImageRemix({
snapshot_media_token: snapshotResult.data!,
disable_system_prompt: !useSystemPrompt,
@@ -423,6 +426,7 @@ export const PromptBox3D = ({
(image) => image.mediaToken
),
maybe_number_of_samples: 1,
aspect_ratio: aspectRatio,
});
console.log("generateResponse", generateResponse);
@@ -517,6 +521,19 @@ export const PromptBox3D = ({
}
};
const getCurrentSoraRemixAspectRatio = () : SoraImageRemixAspectRatio => {
switch (cameraAspectRatio.value) {
case CameraAspectRatio.HORIZONTAL_3_2:
return SoraImageRemixAspectRatio.Wide;
case CameraAspectRatio.VERTICAL_2_3:
case CameraAspectRatio.VERTICAL_9_16:
return SoraImageRemixAspectRatio.Tall;
case CameraAspectRatio.SQUARE_1_1:
default:
return SoraImageRemixAspectRatio.Square;
}
}
const handleSaveFrame = async () => {
if (!snapshotCurrentFrame) {
return;
@@ -17,6 +17,15 @@ export interface SoraImageRemixRequest {
// Typically "1"
maybe_number_of_samples: number,
// The aspect ratio of the output image
aspect_ratio?: SoraImageRemixAspectRatio,
}
export enum SoraImageRemixAspectRatio {
Square = "square",
Wide = "wide",
Tall = "tall",
}
export interface SoraImageRemixSuccess extends CommandResult {
@@ -43,13 +52,7 @@ export type SoraImageRemixResult = SoraImageRemixSuccess | SoraImageRemixError;
export const SoraImageRemix = async (request: SoraImageRemixRequest) : Promise<SoraImageRemixResult> => {
try {
return await invoke("sora_image_remix_command", {
request: {
snapshot_media_token: request.snapshot_media_token,
disable_system_prompt: request.disable_system_prompt,
prompt: request.prompt,
maybe_additional_images: request.maybe_additional_images,
maybe_number_of_samples: request.maybe_number_of_samples,
},
request: request,
}) as SoraImageRemixResult;
} catch (error) {
let maybeTypedError = error as CommandResult;