use std::path::Path;
use crate::flatbuf::FlatBuffer;
use crate::source::ModelSource;
use crate::tflite::TfliteSource;
use crate::{FormatError, Result};
fn bad(what: impl Into<String>) -> FormatError {
FormatError::Safetensors(format!("litertlm: {}", what.into()))
}
const SECTION_TFLITE_MODEL: u8 = 3;
const SECTION_SP_TOKENIZER: u8 = 4;
const SECTION_HF_TOKENIZER_ZLIB: u8 = 6;
#[derive(Debug)]
pub struct SectionInfo {
pub begin: usize,
pub end: usize,
pub data_type: u8,
}
pub fn read_sections(header: &[u8]) -> Result<Vec<SectionInfo>> {
if header.len() < 0x20 || &header[0..8] != b"LITERTLM" {
return Err(bad("bad magic"));
}
let major = u32_le(header, 0x08)?;
if major != 1 {
return Err(bad(format!("unsupported major version {major}")));
}
let header_end = u64_le(header, 0x18)? as usize;
if header_end > header.len() || header_end < 0x20 {
return Err(bad("header end out of range"));
}
let fb = FlatBuffer::new(&header[0x20..header_end], None)?;
let root = fb.root();
let sm = fb
.uoffset(root, 1)
.ok_or_else(|| bad("no section_metadata"))?;
let objects = fb.table_vector(sm, 0)?;
let mut out = Vec::with_capacity(objects.len());
for obj in objects {
let begin = fb.scalar_u64(obj, 1).ok_or_else(|| bad("section missing begin"))? as usize;
let end = fb.scalar_u64(obj, 2).ok_or_else(|| bad("section missing end"))? as usize;
let data_type = fb.scalar_u8(obj, 3).unwrap_or(0);
out.push(SectionInfo { begin, end, data_type });
}
Ok(out)
}
pub fn open_litertlm(path: &Path) -> Result<Box<dyn ModelSource>> {
let head = {
use std::io::Read;
let mut f = std::fs::File::open(path)?;
let mut buf = vec![0u8; 1024 * 1024]; let n = f.read(&mut buf)?;
buf.truncate(n);
buf
};
let sections = read_sections(&head)?;
let tflite = sections
.iter()
.find(|s| s.data_type == SECTION_TFLITE_MODEL)
.ok_or_else(|| bad("no TFLiteModel section"))?;
let spm: Option<Vec<u8>> = sections
.iter()
.find(|s| s.data_type == SECTION_SP_TOKENIZER)
.map(|s| {
use std::io::{Read, Seek, SeekFrom};
let mut f = std::fs::File::open(path)?;
f.seek(SeekFrom::Start(s.begin as u64))?;
let mut buf = vec![0u8; s.end - s.begin];
f.read_exact(&mut buf)?;
Ok::<Vec<u8>, FormatError>(buf)
})
.transpose()?;
Ok(Box::new(TfliteSource::load_at_with_spm(
path,
tflite.begin,
spm.as_deref(),
)?))
}
fn u32_le(d: &[u8], pos: usize) -> Result<u32> {
let b = d.get(pos..pos + 4).ok_or_else(|| bad("u32 out of bounds"))?;
Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
}
fn u64_le(d: &[u8], pos: usize) -> Result<u64> {
let b = d.get(pos..pos + 8).ok_or_else(|| bad("u64 out of bounds"))?;
Ok(u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]))
}