Compare commits

...
Author SHA1 Message Date
Brandon Thomas 2e4a7df1bf video aspect ratio controls appear to do nothing 2025-12-01 00:14:33 -05:00
Brandon Thomas b18ef8265a aspect ratio controls 2025-11-27 03:12:02 -05:00
Brandon Thomas b4f8a54e75 grok video aspect ratio 2025-11-27 03:04:16 -05:00
12 changed files with 212 additions and 7 deletions
@@ -0,0 +1,13 @@
use serde::Serialize;
#[derive(Serialize, Clone, Copy, Debug)]
pub enum AspectRatio {
#[serde(rename = "2:3")]
TallTwoByThree,
#[serde(rename = "3:2")]
WideThreeByTwo,
#[serde(rename = "1:1")]
Square,
}
@@ -1,3 +1,4 @@
pub mod aspect_ratio;
pub mod baggage;
pub mod file_id;
pub mod post_id;
@@ -1,4 +1,5 @@
use crate::credentials::grok_full_credentials::GrokFullCredentials;
use crate::datatypes::api::aspect_ratio::AspectRatio;
use crate::datatypes::api::file_id::FileId;
use crate::datatypes::api::post_id::PostId;
use crate::datatypes::file_upload_spec::FileUploadSpec;
@@ -23,6 +24,9 @@ pub struct UploadImageAndGenerateVideo<'a, P: AsRef<Path>> {
/// Video generation prompt
pub prompt: Option<&'a str>,
/// Aspect ratio for the video.
pub aspect_ratio: Option<AspectRatio>,
/// Wait for the full video to be generated before returning
/// By default, the endpoint stays open for 30-ish seconds while
/// the video generates and streams back JSON progress updates.
@@ -101,6 +105,9 @@ pub async fn upload_image_and_generate_video<P: AsRef<Path>>(args: UploadImageAn
info!("Posted Image.");
info!("Video prompt: {:?}", args.prompt);
info!("Video aspect ratio: {:?}", args.aspect_ratio);
info!("Generate video...");
let request = GrokVideoGenChatConversationBuilder {
@@ -109,6 +116,7 @@ pub async fn upload_image_and_generate_video<P: AsRef<Path>>(args: UploadImageAn
media_type: VideoMediaPostType::UserUploadedImage,
cookie: args.full_credentials.cookies.as_str(),
prompt: args.prompt,
aspect_ratio: args.aspect_ratio,
request_timeout: args.individual_request_timeout,
baggage: &args.full_credentials.client_secrets.baggage,
sentry_trace: &args.full_credentials.client_secrets.sentry_trace,
@@ -177,7 +185,7 @@ mod tests {
use crate::test_utils::setup_test_logging::setup_test_logging;
use errors::AnyhowResult;
use log::LevelFilter;
use crate::datatypes::api::aspect_ratio::AspectRatio;
// Result: GrokUploadFileResponse { file_metadata_id:
// Some("acdee48f-9d6f-4bc6-9d06-fcc97dd4418a"), file_uri:
// Some("users/85980643-ffab-4984-a3de-59a608c47d7f/acdee48f-9d6f-4bc6-9d06-fcc97dd4418a/content") }
@@ -211,6 +219,7 @@ mod tests {
full_credentials: &credentials,
file: FileUploadSpec::Path(image_path),
prompt: maybe_prompt,
aspect_ratio: Some(AspectRatio::Square),
individual_request_timeout: None,
wait_for_generation: false,
}).await?;
@@ -0,0 +1,23 @@
curl 'https://grok.com/rest/app-chat/conversations/new' \
-H 'accept: */*' \
-H 'accept-language: en-US,en;q=0.9' \
-H 'baggage: sentry-environment=production,sentry-public_key=b311e0f2690c81f25e2c4cf6d4f7ce1c,sentry-trace_id=a0dfe5fb521c4aff81dc8e4c29ddf512,sentry-org_id=4508179396558848,sentry-transaction=%2F%3Aslug*%3F,sentry-sampled=false,sentry-sample_rand=0.2766847188981013,sentry-sample_rate=0' \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-b '_ga=GA1.1.1232202746.1760710013; i18nextLng=en; sso=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzZXNzaW9uX2lkIjoiOGU3MDFiNzctOTdkNC00ZjM0LWExOTctOWFmMDU1MzY3NDAwIn0.-a6x0InxbGzfTVfUlrdzxskxCnvMDI8lC90z4wHeGIk; sso-rw=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzZXNzaW9uX2lkIjoiOGU3MDFiNzctOTdkNC00ZjM0LWExOTctOWFmMDU1MzY3NDAwIn0.-a6x0InxbGzfTVfUlrdzxskxCnvMDI8lC90z4wHeGIk; stblid=b3331fc1-45d7-466b-83df-67427c0b2367; x-userid=85980643-ffab-4984-a3de-59a608c47d7f; cf_clearance=_kkd42wRt_Q2aVTB3qvDnUe8BZj7wJA5tYQ.SruABFE-1764222553-1.2.1.1-2U5UwW9vy4CXMEktGjlRBBtDSPkect5mmH5T98k7blNsLt_Mkxum6WZrSkwvTrujXz54E3k46_0elKO.37jq_sU2C.CoCmQ8FxU85JIPG05ybIx26PQkS54vvnnKDtvc7Jcat56FTRzKO8x._p4umwZZWsSSuthdvP9ogWyODnacVg7jyEnJ_KtZInJeLJOwUyL7qxLDTze0yIs9lfXuDzvCQrak4vl2P3FF9q0P1dA; mp_ea93da913ddb66b6372b89d97b1029ac_mixpanel=%7B%22distinct_id%22%3A%2285980643-ffab-4984-a3de-59a608c47d7f%22%2C%22%24device_id%22%3A%2279ce237a-a0f3-4913-bf4b-519ac8a98263%22%2C%22%24initial_referrer%22%3A%22%24direct%22%2C%22%24initial_referring_domain%22%3A%22%24direct%22%2C%22__mps%22%3A%7B%7D%2C%22__mpso%22%3A%7B%7D%2C%22__mpus%22%3A%7B%7D%2C%22__mpa%22%3A%7B%7D%2C%22__mpu%22%3A%7B%7D%2C%22__mpr%22%3A%5B%5D%2C%22__mpap%22%3A%5B%5D%2C%22%24user_id%22%3A%2285980643-ffab-4984-a3de-59a608c47d7f%22%7D; _ga_8FEWB057YH=GS2.1.s1764228571$o20$g1$t1764228595$j36$l0$h0' \
-H 'origin: https://grok.com' \
-H 'pragma: no-cache' \
-H 'priority: u=1, i' \
-H 'referer: https://grok.com/imagine/post/51bc87b7-d985-486b-87f9-2345f9329675' \
-H 'sec-ch-ua: "Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
-H 'sec-fetch-dest: empty' \
-H 'sec-fetch-mode: cors' \
-H 'sec-fetch-site: same-origin' \
-H 'sentry-trace: a0dfe5fb521c4aff81dc8e4c29ddf512-9498b36577293fef-0' \
-H 'traceparent: 00-88e6010c9ecea790a91d0b27c38fd0e1-fac74f63c226ad4f-00' \
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36' \
-H 'x-statsig-id: F6uioputjm5qWZ97AsfHQy+xxfuYSos+nBN7lvk1K0RxkSYiOP3iuyRLttV62pbJK5ONzxM3lf1JMZXxkVl8vNszvMiIFA' \
-H 'x-xai-request-id: 1e445b21-9e73-4cb3-af6d-7918900fab62' \
--data-raw '{"temporary":true,"modelName":"grok-3","message":"https://assets.grok.com/users/85980643-ffab-4984-a3de-59a608c47d7f/51bc87b7-d985-486b-87f9-2345f9329675/content --mode=normal","fileAttachments":["51bc87b7-d985-486b-87f9-2345f9329675"],"toolOverrides":{"videoGen":true},"responseMetadata":{"modelConfigOverride":{"modelMap":{"videoGenModelConfig":{"parentPostId":"51bc87b7-d985-486b-87f9-2345f9329675","aspectRatio":"1:1","videoLength":6}}}}}'
@@ -0,0 +1,23 @@
curl 'https://grok.com/rest/app-chat/conversations/new' \
-H 'accept: */*' \
-H 'accept-language: en-US,en;q=0.9' \
-H 'baggage: sentry-environment=production,sentry-public_key=b311e0f2690c81f25e2c4cf6d4f7ce1c,sentry-trace_id=a0dfe5fb521c4aff81dc8e4c29ddf512,sentry-org_id=4508179396558848,sentry-transaction=%2F%3Aslug*%3F,sentry-sampled=false,sentry-sample_rand=0.2766847188981013,sentry-sample_rate=0' \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-b '_ga=GA1.1.1232202746.1760710013; i18nextLng=en; sso=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzZXNzaW9uX2lkIjoiOGU3MDFiNzctOTdkNC00ZjM0LWExOTctOWFmMDU1MzY3NDAwIn0.-a6x0InxbGzfTVfUlrdzxskxCnvMDI8lC90z4wHeGIk; sso-rw=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzZXNzaW9uX2lkIjoiOGU3MDFiNzctOTdkNC00ZjM0LWExOTctOWFmMDU1MzY3NDAwIn0.-a6x0InxbGzfTVfUlrdzxskxCnvMDI8lC90z4wHeGIk; stblid=b3331fc1-45d7-466b-83df-67427c0b2367; x-userid=85980643-ffab-4984-a3de-59a608c47d7f; cf_clearance=_kkd42wRt_Q2aVTB3qvDnUe8BZj7wJA5tYQ.SruABFE-1764222553-1.2.1.1-2U5UwW9vy4CXMEktGjlRBBtDSPkect5mmH5T98k7blNsLt_Mkxum6WZrSkwvTrujXz54E3k46_0elKO.37jq_sU2C.CoCmQ8FxU85JIPG05ybIx26PQkS54vvnnKDtvc7Jcat56FTRzKO8x._p4umwZZWsSSuthdvP9ogWyODnacVg7jyEnJ_KtZInJeLJOwUyL7qxLDTze0yIs9lfXuDzvCQrak4vl2P3FF9q0P1dA; mp_ea93da913ddb66b6372b89d97b1029ac_mixpanel=%7B%22distinct_id%22%3A%2285980643-ffab-4984-a3de-59a608c47d7f%22%2C%22%24device_id%22%3A%2279ce237a-a0f3-4913-bf4b-519ac8a98263%22%2C%22%24initial_referrer%22%3A%22%24direct%22%2C%22%24initial_referring_domain%22%3A%22%24direct%22%2C%22__mps%22%3A%7B%7D%2C%22__mpso%22%3A%7B%7D%2C%22__mpus%22%3A%7B%7D%2C%22__mpa%22%3A%7B%7D%2C%22__mpu%22%3A%7B%7D%2C%22__mpr%22%3A%5B%5D%2C%22__mpap%22%3A%5B%5D%2C%22%24user_id%22%3A%2285980643-ffab-4984-a3de-59a608c47d7f%22%7D; _ga_8FEWB057YH=GS2.1.s1764228571$o20$g1$t1764228668$j60$l0$h0' \
-H 'origin: https://grok.com' \
-H 'pragma: no-cache' \
-H 'priority: u=1, i' \
-H 'referer: https://grok.com/imagine/post/b0b88b45-9724-49bd-a82c-c83ddcd2937f' \
-H 'sec-ch-ua: "Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
-H 'sec-fetch-dest: empty' \
-H 'sec-fetch-mode: cors' \
-H 'sec-fetch-site: same-origin' \
-H 'sentry-trace: a0dfe5fb521c4aff81dc8e4c29ddf512-8d3208b7533c8446-0' \
-H 'traceparent: 00-46471c2129f7b3cac9db10d504ba132a-7851e787db05c657-00' \
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36' \
-H 'x-statsig-id: T/P6+sP11jYyAccjWp+fG3fpnaPAEtNmxEsjzqFtcxwpyX56YKW643wT7o0igs6Rc6TVl0smbLBKnHfKsZhcEQxzyvdlTA' \
-H 'x-xai-request-id: 9c853e9c-ce87-403b-a2c9-d073523b34f6' \
--data-raw '{"temporary":true,"modelName":"grok-3","message":"A waterspout wrecks an oil tanker, misty, huge waves --mode=custom","toolOverrides":{"videoGen":true},"responseMetadata":{"modelConfigOverride":{"modelMap":{"videoGenModelConfig":{"parentPostId":"b0b88b45-9724-49bd-a82c-c83ddcd2937f","aspectRatio":"2:3","videoLength":6}}}}}'
@@ -1,4 +1,5 @@
use crate::client::browser_user_agents::FIREFOX_143_MAC_USER_AGENT;
use crate::datatypes::api::aspect_ratio::AspectRatio;
use crate::datatypes::api::baggage::Baggage;
use crate::datatypes::api::file_id::FileId;
use crate::datatypes::api::sentry_trace::SentryTrace;
@@ -14,7 +15,7 @@ use crate::requests::index_page::signature::generate_xsid::{generate_xsid, Gener
use crate::requests::upload_file::grok_upload_file::{GrokUploadFile, GrokUploadFileResponse};
use crate::requests::video_chat::parse_video_id::parse_video_id;
use crate::requests::video_chat::parse_video_id_from_partial_byte_stream_buffer::parse_video_id_from_partial_byte_stream_buffer;
use crate::requests::video_chat::request::{CreateChatConversationWireRequest, ModelConfigOverride, ModelMap, ResponseMetadata, ToolOverrides, VideoGenModelConfig};
use crate::requests::video_chat::request::{CreateChatConversationWireRequest, ModelConfigOverride, ModelMap, ResponseMetadata, ToolOverrides, VideoGenAspectRatio, VideoGenModelConfig};
use crate::utils::user_and_file_id_to_image_url::user_and_file_id_to_image_url;
use futures::StreamExt;
use log::{debug, error, info, warn};
@@ -32,6 +33,7 @@ pub struct GrokVideoGenChatConversationBuilder<'a> {
pub file_id: &'a FileId,
pub media_type: VideoMediaPostType,
pub prompt: Option<&'a str>,
pub aspect_ratio: Option<AspectRatio>,
pub cookie: &'a str,
pub user_id: &'a UserId,
@@ -236,6 +238,13 @@ impl <'a> GrokVideoGenChatConversationBuilder<'a> {
prompt = format!("{media_url} {user_prompt} --mode=custom");
}
let aspect_ratio = match self.aspect_ratio {
Some(AspectRatio::Square) => VideoGenAspectRatio::Square,
Some(AspectRatio::WideThreeByTwo) => VideoGenAspectRatio::WideThreeByTwo,
Some(AspectRatio::TallTwoByThree) => VideoGenAspectRatio::TallTwoByThree,
None => VideoGenAspectRatio::WideThreeByTwo,
};
let request_body = CreateChatConversationWireRequest {
temporary: true,
model_name: "grok-3".to_string(),
@@ -251,6 +260,8 @@ impl <'a> GrokVideoGenChatConversationBuilder<'a> {
model_map: ModelMap {
video_gen_model_config: VideoGenModelConfig {
parent_post_id: self.file_id.0.to_string(),
video_length: 6, // NB: API defaults to "6"
aspect_ratio,
},
},
},
@@ -340,6 +351,7 @@ mod tests {
file_id: &file_id,
media_type: VideoMediaPostType::UserUploadedImage,
prompt: maybe_prompt,
aspect_ratio: Some(AspectRatio::TallTwoByThree),
cookie: cookies.as_str(),
user_id: &secrets.user_id,
@@ -402,6 +414,7 @@ mod tests {
file_id: &file_id,
media_type: VideoMediaPostType::UserUploadedImage,
prompt: maybe_prompt,
aspect_ratio: Some(AspectRatio::Square),
cookie: cookies.as_str(),
user_id: &secrets.user_id,
@@ -51,10 +51,55 @@ pub (super) struct ModelMap {
pub (super) struct VideoGenModelConfig {
#[serde(rename = "parentPostId")]
pub (super) parent_post_id: String,
/// Newer field as of November
/// values: "1:1", "2:3" (tall),
#[serde(rename = "aspectRatio")]
pub (super) aspect_ratio: VideoGenAspectRatio,
/// Newer field as of November
/// default seems to be "6"
#[serde(rename = "videoLength")]
pub (super) video_length: u32,
}
#[derive(Serialize, Clone, Copy, Debug)]
pub (super) enum VideoGenAspectRatio {
#[serde(rename = "2:3")]
TallTwoByThree,
#[serde(rename = "3:2")]
WideThreeByTwo,
#[serde(rename = "1:1")]
Square,
}
/*
November 27 no image (text only) square aspect ratio -
--data-raw
{
"temporary":true,
"modelName":"grok-3",
"message":"A waterspout wrecks an oil tanker, misty, huge waves --mode=custom",
"toolOverrides": {
"videoGen":true
},
"responseMetadata": {
"modelConfigOverride": {
"modelMap": {
"videoGenModelConfig": {
"parentPostId":"b0b88b45-9724-49bd-a82c-c83ddcd2937f",
"aspectRatio":"2:3",
"videoLength":6
}
}
}
}
}
October 29 request struct -
--data-raw
@@ -113,4 +158,6 @@ October 22 request struct -
"videoGen":true
}
}
*/
*/
@@ -88,6 +88,10 @@ pub struct EnqueueImageToVideoRequest {
/// Only for Sora2 model currently.
pub sora_orientation: Option<SoraOrientation>,
/// OPTIONAL.
/// Only for Grok model currently
pub grok_aspect_ratio: Option<GrokAspectRatio>,
/// OPTIONAL.
/// Name of the frontend caller.
/// We'll use this to selectively trigger events.
@@ -112,6 +116,15 @@ pub enum SoraOrientation {
Landscape,
}
// TODO: Not sure how to handle so many different types of video (model) x (services).
#[derive(Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum GrokAspectRatio {
Portrait,
Landscape,
Square
}
#[derive(Serialize)]
pub struct EnqueueImageToVideoSuccessResponse {
}
@@ -1,7 +1,7 @@
use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError};
use crate::core::commands::enqueue::image_edit::enqueue_contextual_edit_image_command::EnqueueContextualEditImageCommand;
use crate::core::commands::enqueue::image_inpaint::enqueue_image_inpaint_command::EnqueueInpaintImageCommand;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, GrokAspectRatio, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
use crate::core::events::generation_events::common::GenerationModel;
@@ -19,6 +19,7 @@ use enums::common::generation_provider::GenerationProvider;
use enums::tauri::tasks::task_type::TaskType;
use grok_client::credentials::grok_cookies::GrokCookies;
use grok_client::credentials::grok_full_credentials::GrokFullCredentials;
use grok_client::datatypes::api::aspect_ratio::AspectRatio;
use grok_client::datatypes::file_upload_spec::FileUploadSpec;
use grok_client::recipes::request_client_secrets::{request_client_secrets, RequestClientSecretsArgs};
use grok_client::recipes::upload_image_and_generate_video::{upload_image_and_generate_video, UploadImageAndGenerateVideo};
@@ -55,12 +56,20 @@ pub async fn handle_grok_video(
image_token,
).await?;
let aspect_ratio = match request.grok_aspect_ratio {
None => AspectRatio::WideThreeByTwo,
Some(GrokAspectRatio::Landscape) => AspectRatio::WideThreeByTwo,
Some(GrokAspectRatio::Portrait) => AspectRatio::TallTwoByThree,
Some(GrokAspectRatio::Square) => AspectRatio::Square,
};
info!("Calling Grok Video generate...");
let upload = upload_image_and_generate_video(UploadImageAndGenerateVideo {
full_credentials: &creds,
file: FileUploadSpec::Path(local_image_file.path()),
prompt: request.prompt.as_deref(),
aspect_ratio: Some(aspect_ratio),
wait_for_generation: false,
individual_request_timeout: Some(GROK_IMAGE_UPLOAD_TIMEOUT)
}).await;
@@ -35,6 +35,8 @@ import type { UploadImageFn } from "./ImagePromptRow";
import { twMerge } from "tailwind-merge";
import { toast } from "@storyteller/ui-toaster";
type GROK_ASPECT_RATIO = "landscape" | "portrait" | "square";
const DEFAULT_RESOLUTIONS: SizeOption[] = [
{
tauriValue: "720p",
@@ -205,6 +207,7 @@ export const PromptBoxVideo = ({
}, [isImageRowVisible, onImageRowVisibilityChange]);
const handleResolutionSelect = (selectedItem: PopoverItem) => {
console.log(">>>> handleResolutionSelect", selectedItem);
setResolution(selectedItem.label as any);
setResolutionList((prev) =>
resolutionOptions.map((item) => ({
@@ -284,9 +287,15 @@ export const PromptBoxVideo = ({
request.generate_audio = !!generateWithSound;
}
if (selectedModel?.tauriId === "sora_2") {
request.sora_orientation =
resolution === "720p" ? "landscape" : "portrait";
switch (selectedModel?.tauriId) {
case "grok_video":
request.grok_aspect_ratio = getGrokAspectRatio();
break;
case "sora_2":
request.sora_orientation =
resolution === "720p" ? "landscape" : "portrait";
break;
}
await EnqueueImageToVideo(request);
@@ -319,6 +328,26 @@ export const PromptBoxVideo = ({
}
};
const getGrokAspectRatio = (): GROK_ASPECT_RATIO => {
// NB: This function was just written to give us better type safety.
// There has to be a cleaner appraoach.
const maybeAspectRatio = selectedModel?.
sizeOptions?.
find((option) => option.textLabel === resolution)?.
tauriValue;
switch (maybeAspectRatio) {
case "landscape":
return "landscape";
case "portrait":
return "portrait";
case "square":
return "square";
default:
return "landscape";
}
}
const [isGalleryModalOpen, setIsGalleryModalOpen] = useState(false);
const modelNeedsAnImageButNoneAreSelected =
@@ -16,6 +16,23 @@ export const VIDEO_MODELS: VideoModel[] = [
endFrame: false,
requiresImage: true,
progressBarTime: 50000,
sizeOptions: [
{
tauriValue: "landscape",
textLabel: "Landscape",
icon: SizeIconOption.Landscape,
},
{
tauriValue: "portrait",
textLabel: "Portrait",
icon: SizeIconOption.Portrait,
},
{
tauriValue: "square",
textLabel: "Square",
icon: SizeIconOption.Square,
},
],
}),
new VideoModel({
id: "kling_1_6_pro",
@@ -35,6 +35,9 @@ export interface EnqueueImageToVideoRequest {
// Optional. Orientation of the video for Sora 2.
sora_orientation?: "portrait" | "landscape";
// Optional. Aspect Ratio for the video for Grok Video.
grok_aspect_ratio?: "portrait" | "landscape" | "square";
// Optional. Whether to generate audio alongside the video (used by some models like Veo2)
generate_audio?: boolean;
}
@@ -47,6 +50,7 @@ interface RawEnqueueImageToVideoRequest {
frontend_caller?: string;
frontend_subscriber_id?: string;
sora_orientation?: "portrait" | "landscape";
grok_aspect_ratio?: "portrait" | "landscape" | "square";
generate_audio?: boolean;
}
@@ -94,6 +98,10 @@ export const EnqueueImageToVideo = async (
mutableRequest.sora_orientation = request.sora_orientation;
}
if (request.grok_aspect_ratio) {
mutableRequest.grok_aspect_ratio = request.grok_aspect_ratio;
}
if (typeof request.generate_audio === "boolean") {
mutableRequest.generate_audio = request.generate_audio;
}