grok generation modes

This commit is contained in:
Brandon Thomas committed 2025-12-02 14:10:49 -05:00
1 parent 21a30bde2d
commit 736ac055cc
13 files changed
+312 -5

No files matched your search

@@ -1,6 +1,7 @@
pub mod aspect_ratio;
pub mod baggage;
pub mod file_id;
pub mod video_generation_mode;
pub mod post_id;
pub mod request_id;
pub mod sentry_trace;
@@ -0,0 +1,27 @@
/// The video generation mode selector.
#[derive(Copy, Clone, Debug)]
pub enum VideoGenerationMode {
/// Supposedly the "NSFW" mode.
Spicy,
Fun,
Normal,
/// This might be the only mode that allows for a custom text prompt
Custom,
}
impl VideoGenerationMode {
/// This is the value for `--mode` in video generation chats.
pub fn as_api_mode_arg(&self) -> &'static str {
match self {
Self::Spicy => "extremely-spicy-or-crazy",
Self::Fun => "extremely-crazy",
Self::Normal => "normal",
Self::Custom => "custom",
}
}
}
@@ -92,6 +92,8 @@ mod tests {
cookies: cookies.as_str(),
}).await?;
let prompt = "A dinosaur on stilts walking on the beach";
//let websocket = GrokWrappedWebsocket::new(websocket);
let mut websocket = GrokWebsocket::new(websocket);
@@ -106,7 +108,7 @@ mod tests {
let result = prompt_websocket_image_with_retry(PromptWebsocketImageWithRetryArgs {
websocket: &mut websocket,
prompt: "a dog riding a motorcycle",
prompt,
aspect_ratio: ClientMessageAspectRatio::WideThreeByTwo,
cookies: &cookies,
}).await?;
@@ -152,9 +154,19 @@ mod tests {
match message {
WebsocketServerMessage::Image(image) => {
println!("IMAGE: {:?}", image.percentage_complete);
if let Some(percent) = image.percentage_complete {
if percent > 90.0 {
println!("Image: {:?}", image);
}
}
}
WebsocketServerMessage::Json(json) => {
println!("JSON : {:?}", json.percentage_complete);
if let Some(percent) = json.percentage_complete {
if percent > 90.0 {
println!("Image: {:?}", json);
}
}
}
WebsocketServerMessage::Unknown(unknown) => {
//let typ = unknown.get("type");
@@ -2,6 +2,7 @@ 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::api::video_generation_mode::VideoGenerationMode;
use crate::datatypes::file_upload_spec::FileUploadSpec;
use crate::error::grok_error::GrokError;
use crate::error::grok_generic_api_error::GrokGenericApiError;
@@ -27,6 +28,9 @@ pub struct UploadImageAndGenerateVideo<'a, P: AsRef<Path>> {
/// Aspect ratio for the video.
pub aspect_ratio: Option<AspectRatio>,
/// Mode to generate the video: normal, fun, spicy, etc.
pub mode: Option<VideoGenerationMode>,
/// 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.
@@ -116,6 +120,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,
mode: args.mode,
aspect_ratio: args.aspect_ratio,
request_timeout: args.individual_request_timeout,
baggage: &args.full_credentials.client_secrets.baggage,
@@ -178,6 +183,7 @@ pub async fn upload_image_and_generate_video<P: AsRef<Path>>(args: UploadImageAn
#[cfg(test)]
mod tests {
use crate::credentials::grok_full_credentials::GrokFullCredentials;
use crate::datatypes::api::aspect_ratio::AspectRatio;
use crate::datatypes::file_upload_spec::FileUploadSpec;
use crate::recipes::request_client_secrets::{request_client_secrets, RequestClientSecretsArgs};
use crate::recipes::upload_image_and_generate_video::{upload_image_and_generate_video, UploadImageAndGenerateVideo};
@@ -185,7 +191,6 @@ 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") }
@@ -220,6 +225,7 @@ mod tests {
file: FileUploadSpec::Path(image_path),
prompt: maybe_prompt,
aspect_ratio: Some(AspectRatio::Square),
mode: None,
individual_request_timeout: None,
wait_for_generation: false,
}).await?;
@@ -1,6 +1,7 @@
use crate::credentials::grok_client_secrets::GrokClientSecrets;
use crate::credentials::grok_full_credentials::GrokFullCredentials;
use crate::datatypes::api::aspect_ratio::AspectRatio;
use crate::datatypes::api::video_generation_mode::VideoGenerationMode;
use crate::datatypes::file_upload_spec::FileUploadSpec;
use crate::error::grok_client_error::GrokClientError;
use crate::error::grok_error::GrokError;
@@ -30,6 +31,9 @@ pub struct UploadImageAndGenerateVideoWithRetry<'a, P: AsRef<Path>> {
/// Aspect ratio for the video.
pub aspect_ratio: Option<AspectRatio>,
/// Mode to generate the video: normal, fun, spicy, etc.
pub mode: Option<VideoGenerationMode>,
/// 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.
@@ -116,6 +120,7 @@ pub async fn upload_image_and_generate_video_with_retry<P: AsRef<Path>>(
media_type: VideoMediaPostType::UserUploadedImage,
cookie: current_full_credentials_ref.cookies.as_str(),
prompt: args.prompt,
mode: args.mode,
aspect_ratio: args.aspect_ratio,
request_timeout: args.individual_request_timeout,
baggage: &current_full_credentials_ref.client_secrets.baggage,
@@ -271,6 +276,7 @@ pub async fn upload_image_and_generate_video_with_retry<P: AsRef<Path>>(
mod tests {
use crate::credentials::grok_full_credentials::GrokFullCredentials;
use crate::datatypes::api::aspect_ratio::AspectRatio;
use crate::datatypes::api::video_generation_mode::VideoGenerationMode;
use crate::datatypes::file_upload_spec::FileUploadSpec;
use crate::recipes::request_client_secrets::{request_client_secrets, RequestClientSecretsArgs};
use crate::recipes::upload_image_and_generate_video_with_retry::{upload_image_and_generate_video_with_retry, UploadImageAndGenerateVideoWithRetry};
@@ -310,7 +316,8 @@ mod tests {
credentials: &credentials,
file: FileUploadSpec::Path(image_path),
prompt: maybe_prompt,
aspect_ratio: Some(AspectRatio::Square),
mode: Some(VideoGenerationMode::Custom),
aspect_ratio: Some(AspectRatio::TallTwoByThree),
individual_request_timeout: None,
wait_for_generation: false,
}).await?;
@@ -0,0 +1,45 @@
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=7798e88fd61243ba8985ca9f589f5113,sentry-org_id=4508179396558848,sentry-transaction=%2F%3Aslug*%3F,sentry-sampled=false,sentry-sample_rand=0.01740155041905489,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; 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; cf_clearance=5QPOzLWH8eEniaDlJR23k9VB4XjRPHdR.kfVR15BRkI-1764645588-1.2.1.1-WBy8wpvS9.Q.ofWBIMTLHDrKRIPt0Xrn5kAQ6I7xf4u0JSbB.E4CRd.fK6kEZo8OTXMAdt.F0YkoLJzB0TufxM79dMu63TKLmorKB.gSgUWJcea1eQcLJ1WG80uhv4VCMrSJ_HHAaq6fqiNNvS7pArgMT4tvoaQXShfDuV8ivYsRp31LYMgNnRFdtiCiJ5mxhf7uUMpSS_UbvCSaYe7CysUr472alMjEYUd.QhKpb8E; _ga_8FEWB057YH=GS2.1.s1764645588$o22$g1$t1764646543$j57$l0$h0' \
-H 'origin: https://grok.com' \
-H 'pragma: no-cache' \
-H 'priority: u=1, i' \
-H 'referer: https://grok.com/imagine/post/463eb5f6-7485-495a-a344-70ab4fe454a9' \
-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: 7798e88fd61243ba8985ca9f589f5113-889cac2356ac270b-0' \
-H 'traceparent: 00-9698441276035e5f4414a5c7b7cde4e7-043b158b0070e175-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: eVTlFkyAcCo5RWxUQOUfzewYmzWMb/GbAFj4n2ymSal+UQwbGGxtFMSDrd+DdsVB0EaFp33Dd+aDMEmMn9Ay0MCCa8Bqeg' \
-H 'x-xai-request-id: ac5e2fc3-daed-4967-a9ff-1d12b60ee0e1' \
--data-raw '{"temporary":true,"modelName":"grok-3","message":"https://imagine-public.x.ai/imagine-public/images/463eb5f6-7485-495a-a344-70ab4fe454a9.png --mode=extremely-crazy","toolOverrides":{"videoGen":true},"responseMetadata":{"modelConfigOverride":{"modelMap":{"videoGenModelConfig":{"parentPostId":"463eb5f6-7485-495a-a344-70ab4fe454a9","aspectRatio":"2:3","videoLength":6}}}}}'
--data-raw
{
"temporary":true,
"modelName":"grok-3",
"message":"https://imagine-public.x.ai/imagine-public/images/463eb5f6-7485-495a-a344-70ab4fe454a9.png --mode=extremely-crazy",
"toolOverrides": {
"videoGen":true
},
"responseMetadata": {
"modelConfigOverride": {
"modelMap": {
"videoGenModelConfig": {
"parentPostId":"463eb5f6-7485-495a-a344-70ab4fe454a9",
"aspectRatio": "2:3",
"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=7798e88fd61243ba8985ca9f589f5113,sentry-org_id=4508179396558848,sentry-transaction=%2F%3Aslug*%3F,sentry-sampled=false,sentry-sample_rand=0.01740155041905489,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; 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; cf_clearance=5QPOzLWH8eEniaDlJR23k9VB4XjRPHdR.kfVR15BRkI-1764645588-1.2.1.1-WBy8wpvS9.Q.ofWBIMTLHDrKRIPt0Xrn5kAQ6I7xf4u0JSbB.E4CRd.fK6kEZo8OTXMAdt.F0YkoLJzB0TufxM79dMu63TKLmorKB.gSgUWJcea1eQcLJ1WG80uhv4VCMrSJ_HHAaq6fqiNNvS7pArgMT4tvoaQXShfDuV8ivYsRp31LYMgNnRFdtiCiJ5mxhf7uUMpSS_UbvCSaYe7CysUr472alMjEYUd.QhKpb8E; _ga_8FEWB057YH=GS2.1.s1764645588$o22$g1$t1764646543$j57$l0$h0' \
-H 'origin: https://grok.com' \
-H 'pragma: no-cache' \
-H 'priority: u=1, i' \
-H 'referer: https://grok.com/imagine/post/463eb5f6-7485-495a-a344-70ab4fe454a9' \
-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: 7798e88fd61243ba8985ca9f589f5113-ac16ba34e7a9e3c2-0' \
-H 'traceparent: 00-017b734e99d0585d4e05bf0376ef9ffb-c5854dfb0968df83-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: 8dxtnsQI+KKxzeTcyG2XRWSQE70E53kTiNBwF+QuwSH22YSTkOTlnEwLJVcL/k3JWIkNL/XNm7U/U87VShlyvfCIJ01k8g' \
-H 'x-xai-request-id: c2eab60f-859f-4963-8ef8-b5eefaaf5966' \
--data-raw '{"temporary":true,"modelName":"grok-3","message":"https://imagine-public.x.ai/imagine-public/images/463eb5f6-7485-495a-a344-70ab4fe454a9.png --mode=normal","toolOverrides":{"videoGen":true},"responseMetadata":{"modelConfigOverride":{"modelMap":{"videoGenModelConfig":{"parentPostId":"463eb5f6-7485-495a-a344-70ab4fe454a9","aspectRatio":"2:3","videoLength":6}}}}}'
@@ -0,0 +1,46 @@
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=277d6351c5063fd659b51b77b50bb453,sentry-org_id=4508179396558848,sentry-sampled=false,sentry-sample_rand=0.9765826569629004,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; 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; cf_clearance=5QPOzLWH8eEniaDlJR23k9VB4XjRPHdR.kfVR15BRkI-1764645588-1.2.1.1-WBy8wpvS9.Q.ofWBIMTLHDrKRIPt0Xrn5kAQ6I7xf4u0JSbB.E4CRd.fK6kEZo8OTXMAdt.F0YkoLJzB0TufxM79dMu63TKLmorKB.gSgUWJcea1eQcLJ1WG80uhv4VCMrSJ_HHAaq6fqiNNvS7pArgMT4tvoaQXShfDuV8ivYsRp31LYMgNnRFdtiCiJ5mxhf7uUMpSS_UbvCSaYe7CysUr472alMjEYUd.QhKpb8E; _ga_8FEWB057YH=GS2.1.s1764645588$o22$g1$t1764645617$j31$l0$h0' \
-H 'origin: https://grok.com' \
-H 'pragma: no-cache' \
-H 'priority: u=1, i' \
-H 'referer: https://grok.com/imagine/post/6136f31a-4aaf-48e0-ab86-fe9871feca91' \
-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: 277d6351c5063fd659b51b77b50bb453-928bfb8d1221fde1-0' \
-H 'traceparent: 00-b0bd9846c2990e253ecca887fdfba8a2-c415282f4b74bf60-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: HjOCcSvnF01eIgszJ4J4qot//FLrCJb8Zz+f+AvBLs4ZNmt8fwsKc6PkyrjkEaImt9npwBpAUCrYQeeYTG/5jRWOKfLdHQ' \
-H 'x-xai-request-id: d5ac2ce6-ed77-4a5d-8905-613a498035d3' \
--data-raw '{"temporary":true,"modelName":"grok-3","message":"https://imagine-public.x.ai/imagine-public/images/6136f31a-4aaf-48e0-ab86-fe9871feca91.png --mode=extremely-spicy-or-crazy","toolOverrides":{"videoGen":true},"responseMetadata":{"modelConfigOverride":{"modelMap":{"videoGenModelConfig":{"parentPostId":"6136f31a-4aaf-48e0-ab86-fe9871feca91","aspectRatio":"2:3","videoLength":6}}}}}'
--data-raw
{
"temporary":true,
"modelName":"grok-3",
"message":"https://imagine-public.x.ai/imagine-public/images/6136f31a-4aaf-48e0-ab86-fe9871feca91.png --mode=extremely-spicy-or-crazy",
"toolOverrides": {
"videoGen":true
},
"responseMetadata": {
"modelConfigOverride": {
"modelMap": {
"videoGenModelConfig": {
"parentPostId": "6136f31a-4aaf-48e0-ab86-fe9871feca91",
"aspectRatio": "2:3",
"videoLength":6
}
}
}
}
}
@@ -6,6 +6,7 @@ use crate::datatypes::api::sentry_trace::SentryTrace;
use crate::datatypes::api::svg_path_data::SvgPathData;
use crate::datatypes::api::user_id::UserId;
use crate::datatypes::api::verification_token::VerificationToken;
use crate::datatypes::api::video_generation_mode::VideoGenerationMode;
use crate::datatypes::api::xsid_numbers::XsidNumbers;
use crate::error::categorize_grok_http_error::categorize_grok_http_error;
use crate::error::grok_client_error::GrokClientError;
@@ -33,6 +34,7 @@ pub struct GrokVideoGenChatConversationBuilder<'a> {
pub file_id: &'a FileId,
pub media_type: VideoMediaPostType,
pub prompt: Option<&'a str>,
pub mode: Option<VideoGenerationMode>,
pub aspect_ratio: Option<AspectRatio>,
pub cookie: &'a str,
@@ -232,12 +234,23 @@ impl <'a> GrokVideoGenChatConversationBuilder<'a> {
VideoMediaPostType::Video => unimplemented!("implement for videos"),
};
let mut prompt = format!("{media_url} --mode=normal");
let mode_string = self.mode
.unwrap_or(VideoGenerationMode::Normal)
.as_api_mode_arg();
let mut prompt = format!("{media_url} --mode={mode_string}");
if let Some(user_prompt) = self.prompt {
prompt = format!("{media_url} {user_prompt} --mode=custom");
// If a text prompt is set, mode seems to typically be "custom".
let mode_string = self.mode
.unwrap_or(VideoGenerationMode::Custom)
.as_api_mode_arg();
prompt = format!("{media_url} {user_prompt} --mode={mode_string}");
}
info!("Grok video prompt: {prompt}");
let aspect_ratio = match self.aspect_ratio {
Some(AspectRatio::Square) => VideoGenAspectRatio::Square,
Some(AspectRatio::WideThreeByTwo) => VideoGenAspectRatio::WideThreeByTwo,
@@ -351,6 +364,7 @@ mod tests {
file_id: &file_id,
media_type: VideoMediaPostType::UserUploadedImage,
prompt: maybe_prompt,
mode: Some(VideoGenerationMode::Custom),
aspect_ratio: Some(AspectRatio::TallTwoByThree),
cookie: cookies.as_str(),
@@ -414,6 +428,7 @@ mod tests {
file_id: &file_id,
media_type: VideoMediaPostType::UserUploadedImage,
prompt: maybe_prompt,
mode: None,
aspect_ratio: Some(AspectRatio::Square),
cookie: cookies.as_str(),
+1
View File
@@ -2408,3 +2408,4 @@ pub mod yue;
pub mod zonos;
pub mod qwen_image_edit;
pub mod nano_banana_pro;
@@ -0,0 +1,2 @@
pub mod nano_banana_pro_text_to_image;
pub mod nano_banana_pro_image_edit;
@@ -0,0 +1,69 @@
use crate::prelude::{Deserialize, FalRequest, Serialize};
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct NanoBananaProImageEditInput {
pub prompt: String,
pub image_urls: Vec<String>,
/// Eg. "16:9", "1:1", and a ton of other options. So many options.
pub aspect_ratio: String,
/// Eg. "1K", "2K", "4K"
pub resolution: String,
/// 1 - 4
#[serde(skip_serializing_if = "Option::is_none")]
pub num_images: Option<u8>,
/// "jpeg", "png", "webp"
#[serde(skip_serializing_if = "Option::is_none")]
pub output_format: Option<String>,
}
/*
{
"prompt": "make a photo of the man driving the car down the california coastline",
"num_images": 3,
"aspect_ratio": "16:9",
"output_format": "png",
"image_urls": [
"https://storage.googleapis.com/falserverless/example_inputs/nano-banana-edit-input.png",
"https://storage.googleapis.com/falserverless/example_inputs/nano-banana-edit-input-2.png"
],
"resolution": "1K"
}
*/
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct File {
/// The URL where the file can be downloaded from.
pub url: String,
// /// The mime type of the file.
// /// "image/png"
// #[serde(skip_serializing_if = "Option::is_none")]
// pub content_type: Option<String>,
// /// File data
// #[serde(skip_serializing_if = "Option::is_none")]
// pub file_data: Option<String>,
// /// The name of the file. It will be auto-generated if not provided.
// /// "z9RV14K95DvU.png"
// #[serde(skip_serializing_if = "Option::is_none")]
// pub file_name: Option<String>,
// /// The size of the file in bytes.
// /// 4404019
// #[serde(skip_serializing_if = "Option::is_none")]
// pub file_size: Option<i64>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Gemini25FlashImageEditOutput {
pub images: Vec<File>,
}
pub fn gemini_25_flash_image_edit(
params: Gemini25FlashImageEditInput,
) -> FalRequest<Gemini25FlashImageEditInput, Gemini25FlashImageEditOutput> {
FalRequest::new("fal-ai/gemini-25-flash-image/edit", params)
}
@@ -0,0 +1,53 @@
use crate::prelude::{Deserialize, FalRequest, Serialize};
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct Gemini25FlashImageEditInput {
pub prompt: String,
pub image_urls: Vec<String>,
/// 1 - 4
#[serde(skip_serializing_if = "Option::is_none")]
pub num_images: Option<u8>,
/// "jpeg" or "png"
#[serde(skip_serializing_if = "Option::is_none")]
pub output_format: Option<String>,
// /// Resolution, eg. "720p"
// #[serde(skip_serializing_if = "Option::is_none")]
// pub resolution: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct File {
/// The URL where the file can be downloaded from.
pub url: String,
// /// The mime type of the file.
// /// "image/png"
// #[serde(skip_serializing_if = "Option::is_none")]
// pub content_type: Option<String>,
// /// File data
// #[serde(skip_serializing_if = "Option::is_none")]
// pub file_data: Option<String>,
// /// The name of the file. It will be auto-generated if not provided.
// /// "z9RV14K95DvU.png"
// #[serde(skip_serializing_if = "Option::is_none")]
// pub file_name: Option<String>,
// /// The size of the file in bytes.
// /// 4404019
// #[serde(skip_serializing_if = "Option::is_none")]
// pub file_size: Option<i64>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Gemini25FlashImageEditOutput {
pub images: Vec<File>,
}
pub fn gemini_25_flash_image_edit(
params: Gemini25FlashImageEditInput,
) -> FalRequest<Gemini25FlashImageEditInput, Gemini25FlashImageEditOutput> {
FalRequest::new("fal-ai/gemini-25-flash-image/edit", params)
}