zai-rs 0.6.0

Type-safe async Rust SDK for Zhipu AI (BigModel) APIs
Documentation
//! Asynchronous text-to-video generation.

/// Request builder and client for video generation.
mod data;
/// Supported video-model ids and option enums.
mod video_model;
/// Request body types.
mod video_request;

pub use data::*;
pub use video_model::*;
pub use video_request::*;

#[cfg(test)]
mod tests {
    use serde_json;

    use super::*;
    #[test]
    fn test_video_body_prompt_only_serialization() {
        let model = CogVideoX3 {};
        let video_body = VideoBody::prompt_only(model, "A cat is playing with a ball.")
            .with_quality(VideoQuality::Quality)
            .with_audio(true)
            .with_size(VideoSize::Size1920x1080)
            .with_fps(Fps::Fps30);

        let json = serde_json::to_string(&video_body).unwrap();
        let expected = r#"{"model":"cogvideox-3","prompt":"A cat is playing with a ball.","quality":"quality","with_audio":true,"size":"1920x1080","fps":30}"#;

        assert_eq!(json, expected);
    }

    #[test]
    fn test_video_body_single_image_serialization() {
        let model = CogVideoX3 {};
        let video_body = VideoBody::with_single_image(
            model,
            "https://img.iplaysoft.com/wp-content/uploads/2019/free-images/free_stock_photo.jpg",
            "让画面动起来",
        )
        .with_quality(VideoQuality::Quality)
        .with_audio(true)
        .with_size(VideoSize::Size1920x1080)
        .with_fps(Fps::Fps30);

        let json = serde_json::to_string(&video_body).unwrap();
        let expected = r#"{"model":"cogvideox-3","image_url":"https://img.iplaysoft.com/wp-content/uploads/2019/free-images/free_stock_photo.jpg","prompt":"让画面动起来","quality":"quality","with_audio":true,"size":"1920x1080","fps":30}"#;

        assert_eq!(json, expected);
    }

    #[test]
    fn test_video_body_multiple_images_serialization() {
        let model = CogVideoX3 {};
        let image_urls = vec![
            "https://gd-hbimg.huaban.com/ccee58d77afe8f5e17a572246b1994f7e027657fe9e6-qD66In_fw1200webp",
            "https://gd-hbimg.huaban.com/cc2601d568a72d18d90b2cc7f1065b16b2d693f7fa3f7-hDAwNq_fw1200webp",
        ];
        let video_body = VideoBody::with_multiple_images(model, image_urls, "让画面动起来")
            .unwrap()
            .with_quality(VideoQuality::Quality)
            .with_audio(true)
            .with_size(VideoSize::Size1920x1080)
            .with_fps(Fps::Fps30);

        let json = serde_json::to_string(&video_body).unwrap();
        let expected = r#"{"model":"cogvideox-3","image_url":["https://gd-hbimg.huaban.com/ccee58d77afe8f5e17a572246b1994f7e027657fe9e6-qD66In_fw1200webp","https://gd-hbimg.huaban.com/cc2601d568a72d18d90b2cc7f1065b16b2d693f7fa3f7-hDAwNq_fw1200webp"],"prompt":"让画面动起来","quality":"quality","with_audio":true,"size":"1920x1080","fps":30}"#;

        assert_eq!(json, expected);
    }

    #[test]
    fn test_image_url_base64_serialization() {
        let image_url = ImageUrl::base64("data:image/png;base64,testbase64data");
        let json = serde_json::to_string(&image_url).unwrap();
        let expected = r#""data:image/png;base64,testbase64data""#;

        assert_eq!(json, expected);
    }

    #[test]
    fn test_image_url_single_url_serialization() {
        let image_url = ImageUrl::from_url("https://example.com/image.jpg");
        let json = serde_json::to_string(&image_url).unwrap();
        let expected = r#""https://example.com/image.jpg""#;

        assert_eq!(json, expected);
    }

    #[test]
    fn test_image_url_multiple_urls_serialization() {
        let image_url = ImageUrl::from_two_urls(
            "https://example.com/image1.jpg",
            "https://example.com/image2.jpg",
        );
        let json = serde_json::to_string(&image_url).unwrap();
        let expected = r#"["https://example.com/image1.jpg","https://example.com/image2.jpg"]"#;

        assert_eq!(json, expected);
    }

    #[test]
    fn test_video_quality_serialization() {
        assert_eq!(
            serde_json::to_string(&VideoQuality::Speed).unwrap(),
            r#""speed""#
        );
        assert_eq!(
            serde_json::to_string(&VideoQuality::Quality).unwrap(),
            r#""quality""#
        );
    }

    #[test]
    fn test_video_size_serialization() {
        assert_eq!(
            serde_json::to_string(&VideoSize::Size1920x1080).unwrap(),
            r#""1920x1080""#
        );
        assert_eq!(
            serde_json::to_string(&VideoSize::Size3840x2160).unwrap(),
            r#""3840x2160""#
        );
    }

    #[test]
    fn test_fps_serialization() {
        assert_eq!(serde_json::to_string(&Fps::Fps30).unwrap(), "30");
        assert_eq!(serde_json::to_string(&Fps::Fps60).unwrap(), "60");
    }

    #[test]
    fn test_video_duration_serialization() {
        assert_eq!(
            serde_json::to_string(&VideoDuration::Duration5).unwrap(),
            "5"
        );
        assert_eq!(
            serde_json::to_string(&VideoDuration::Duration10).unwrap(),
            "10"
        );
    }

    #[test]
    fn test_video_body_builder_methods() {
        let model = CogVideoX3 {};
        let video_body = VideoBody::new(model)
            .with_prompt("Test prompt")
            .with_quality(VideoQuality::Speed)
            .with_audio(false)
            .with_size(VideoSize::Size1280x720)
            .with_fps(Fps::Fps60)
            .with_duration(VideoDuration::Duration10);

        let json = serde_json::to_string(&video_body).unwrap();
        assert!(json.contains(r#""prompt":"Test prompt""#));
        assert!(json.contains(r#""quality":"speed""#));
        assert!(json.contains(r#""with_audio":false"#));
        assert!(json.contains(r#""size":"1280x720""#));
        assert!(json.contains(r#""fps":60"#));
        assert!(json.contains(r#""duration":10"#));
    }

    #[test]
    fn test_video_body_skip_none_fields() {
        let model = CogVideoX3 {};
        let video_body = VideoBody::new(model).with_prompt("Test prompt");

        let json = serde_json::to_string(&video_body).unwrap();
        assert!(json.contains(r#""prompt":"Test prompt""#));
        assert!(!json.contains("quality"));
        assert!(!json.contains("with_audio"));
        assert!(!json.contains("size"));
        assert!(!json.contains("fps"));
        assert!(!json.contains("duration"));
    }

    #[test]
    fn video_body_rejects_blank_or_malformed_inputs() {
        use validator::Validate;

        assert!(
            VideoBody::new(CogVideoX3 {})
                .with_prompt("   ")
                .validate()
                .is_err()
        );
        assert!(
            VideoBody::new(CogVideoX3 {})
                .with_image_url(ImageUrl::VecUrl(Vec::new()))
                .validate()
                .is_err()
        );
        assert!(
            VideoBody::new(CogVideoX3 {})
                .with_image_url(ImageUrl::from_url("not-a-url"))
                .validate()
                .is_err()
        );
        assert!(
            VideoBody::new(CogVideoX3 {})
                .with_prompt("valid")
                .with_image_url(ImageUrl::from_url("not-a-url"))
                .validate()
                .is_err()
        );
        assert!(
            VideoBody::new(CogVideoX3 {})
                .with_prompt(" ")
                .with_image_url(ImageUrl::from_url("https://example.com/image.png"))
                .validate()
                .is_err()
        );
        assert!(
            VideoBody::new(CogVideoX3 {})
                .with_image_url(ImageUrl::VecUrl(vec!["a".into(), "b".into(), "c".into()]))
                .validate()
                .is_err()
        );
    }
}