ferrox_models/
vl_engine.rs1use std::path::{Path, PathBuf};
13
14use thiserror::Error;
15
16#[derive(Debug, Error)]
17#[error("multimodal/VL engine not implemented for architecture {arch}")]
18pub struct VlUnavailable {
19 pub arch: String,
20}
21
22#[derive(Debug, Clone)]
24pub struct VlProjectorPair {
25 pub arch: String,
26 pub main_gguf: PathBuf,
27 pub mmproj_gguf: PathBuf,
28}
29
30impl VlProjectorPair {
31 pub fn from_paths(arch: &str, main_gguf: &Path, mmproj_gguf: PathBuf) -> Self {
33 Self {
34 arch: arch.to_string(),
35 main_gguf: main_gguf.to_path_buf(),
36 mmproj_gguf,
37 }
38 }
39}
40
41pub struct VlEngine {
42 pub arch: String,
43 pub projector: Option<VlProjectorPair>,
45}
46
47impl VlEngine {
48 pub fn reject(arch: &str) -> Result<(), VlUnavailable> {
49 Err(VlUnavailable {
50 arch: arch.to_string(),
51 })
52 }
53
54 pub fn reject_with_mmproj(arch: &str, pair: VlProjectorPair) -> Result<(), VlUnavailable> {
56 let _ = pair;
57 Self::reject(arch)
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn reject_is_fail_closed() {
67 assert!(VlEngine::reject("qwen2vl").is_err());
68 }
69
70 #[test]
71 fn projector_pair_records_paths() {
72 let main = Path::new("/tmp/model.gguf");
73 let mm = PathBuf::from("/tmp/mmproj-f16.gguf");
74 let pair = VlProjectorPair::from_paths("qwen2vl", main, mm.clone());
75 assert_eq!(pair.mmproj_gguf, mm);
76 assert!(VlEngine::reject_with_mmproj("qwen2vl", pair).is_err());
77 }
78}