mold_server/
chain_limits.rs1use serde::{Deserialize, Serialize};
8use utoipa::ToSchema;
9
10#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
11pub struct ChainLimits {
12 pub model: String,
13 pub frames_per_clip_cap: u32,
14 pub frames_per_clip_recommended: u32,
15 pub max_stages: u32,
16 pub max_total_frames: u32,
17 pub fade_frames_max: u32,
18 pub transition_modes: Vec<String>,
19 pub quantization_family: String,
20 pub supports_audio: bool,
25}
26
27pub fn family_cap(family: &str) -> Option<u32> {
30 mold_inference::chain::capability_for_family(family).map(|c| c.frames_per_clip_cap)
31}
32
33pub fn family_supports_audio(family: &str) -> bool {
37 mold_inference::chain::capability_for_family(family).is_some_and(|c| c.supports_audio)
38}
39
40pub fn compute_limits(model: &str, family: &str, quant: &str, free_vram_bytes: u64) -> ChainLimits {
46 let cap = family_cap(family).unwrap_or(97);
47 let _ = free_vram_bytes; let recommended = cap;
52
53 const MAX_STAGES: u32 = 16;
54 ChainLimits {
55 model: model.to_string(),
56 frames_per_clip_cap: cap,
57 frames_per_clip_recommended: recommended,
58 max_stages: MAX_STAGES,
59 max_total_frames: cap * MAX_STAGES,
60 fade_frames_max: 32,
61 transition_modes: vec!["smooth".into(), "cut".into(), "fade".into()],
62 quantization_family: quant.to_string(),
63 supports_audio: family_supports_audio(family),
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn ltx2_cap_is_97() {
73 assert_eq!(family_cap("ltx2"), Some(97));
76 }
77
78 #[test]
79 fn ltx_video_cap_is_97() {
80 assert_eq!(family_cap("ltx-video"), Some(97));
84 }
85
86 #[test]
87 fn audio_capability_is_ltx2_only() {
88 assert!(family_supports_audio("ltx2"));
91 assert!(!family_supports_audio("ltx-video"));
92 assert!(!family_supports_audio("flux"));
93 assert!(!family_supports_audio(""));
94 }
95
96 #[test]
97 fn unknown_family_has_no_cap() {
98 assert_eq!(family_cap("flux"), None);
99 assert_eq!(family_cap("sdxl"), None);
100 }
101
102 #[test]
103 fn compute_limits_for_distilled() {
104 let lim = compute_limits("ltx-2-19b-distilled:fp8", "ltx2", "fp8", 8_000_000_000);
105 assert_eq!(lim.frames_per_clip_cap, 97);
106 assert_eq!(lim.frames_per_clip_recommended, 97);
107 assert_eq!(lim.max_stages, 16);
108 assert_eq!(lim.max_total_frames, 97 * 16);
109 assert_eq!(
110 lim.transition_modes,
111 vec!["smooth".to_string(), "cut".into(), "fade".into()]
112 );
113 assert!(
114 lim.supports_audio,
115 "ltx2 family has the AV transformer + audio VAE / vocoder path",
116 );
117 }
118
119 #[test]
120 fn compute_limits_for_ltx_video_has_no_audio() {
121 let lim = compute_limits("ltx-video-0.9.7-distilled:fp8", "ltx-video", "fp8", 0);
124 assert!(
125 !lim.supports_audio,
126 "ltx-video has no audio path — toggle must stay off",
127 );
128 }
129}