diff --git a/crates/api_clients/grok_client/src/recipes/upload_image_and_generate_video.rs b/crates/api_clients/grok_client/src/recipes/upload_image_and_generate_video.rs index abe3ac9c6f..d062b7d618 100644 --- a/crates/api_clients/grok_client/src/recipes/upload_image_and_generate_video.rs +++ b/crates/api_clients/grok_client/src/recipes/upload_image_and_generate_video.rs @@ -105,6 +105,9 @@ pub async fn upload_image_and_generate_video>(args: UploadImageAn info!("Posted Image."); + info!("Video prompt: {:?}", args.prompt); + info!("Video aspect ratio: {:?}", args.aspect_ratio); + info!("Generate video..."); let request = GrokVideoGenChatConversationBuilder { diff --git a/frontend/libs/components/promptbox/src/lib/PromptBoxVideo.tsx b/frontend/libs/components/promptbox/src/lib/PromptBoxVideo.tsx index e39b33b412..1ef73d8abf 100644 --- a/frontend/libs/components/promptbox/src/lib/PromptBoxVideo.tsx +++ b/frontend/libs/components/promptbox/src/lib/PromptBoxVideo.tsx @@ -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 = diff --git a/frontend/libs/tauri-api/src/lib/enqueue/EnqueueImageToVideo.ts b/frontend/libs/tauri-api/src/lib/enqueue/EnqueueImageToVideo.ts index 9b5c264778..c1777bc6db 100644 --- a/frontend/libs/tauri-api/src/lib/enqueue/EnqueueImageToVideo.ts +++ b/frontend/libs/tauri-api/src/lib/enqueue/EnqueueImageToVideo.ts @@ -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; }