"""models//manifest.json: every graph's signatures (input / output names and shapes, read from the flatbuffer), the accelerator and precision it runs at, which matting graph the app uses, and the raw side files (little-endian float32) with their shapes, for the Kotlin app. Also writes gs_perturbation.f32 next to gs_perturbation.npy. python make_manifest.py models/v1 [--dis PATH_TO_dis.tflite] With den_joint_mid.tflite and den_joint_w.f32 in the folder (export_shared_joint.py) and no den_joint_01..22, the manifest lists den_joint_mid in their place with `shared_blocks` [1..22], `block_weights` and `first_weight_input` (the inputs before the weights), and the weights file as a side file [22, floats per block]. gs_mid.tflite and gs_w.f32 (export_shared_gauss.py) with no gs_1..6 likewise stand for gs_1..6. --precision fp16 runs the GPU graphs at FP16 without fp32 accumulation (the default keeps FP16_WITH_FP32_ACCUM). """ import argparse import hashlib import json import os import sys import numpy as np sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from lrt import sig_io # noqa: E402 FP32_GRAPHS = set() # graphs whose fp16 form fails its CONTRACT.md line (none since the key-chunked attention) CPU_GRAPHS = {'bir'} # BiRefNet: its deformable convolutions lower to GATHER_ND, which the LiteRT GPU does not run # A CPU graph's working memory comes with its call, after the compile: how far MemAvailable fell from just before the # compile to the low point of one call on the Galaxy S26 (LiteRT 2.3.0 CPU; device/g2/bir3.samples.txt: 6,492,924 kB # before, 3,760,320 kB lowest = 2,732,604 kB). The app's memory check counts it before BiRefNet runs. RUN_PEAK_BYTES = {'bir': 2_732_604 * 1024} ORDER = (['bir', 'dis'] + [f'dino_{i}' for i in range(4)] + ['vae_0', 'vae_1', 'vae_2', 'vae_3', 'vae_attn', 'vae_4'] + ['den_ctx', 'den_in'] + [f'den_joint_{k:02d}' for k in range(24)] + ['oct'] + [f'gs_{i}' for i in range(8)]) # shared graph -> (the json its export script writes, its weights file, the graph name of block k) SHARED = {'den_joint_mid': ('shared_joint.json', 'den_joint_w.f32', lambda k: f'den_joint_{k:02d}'), 'gs_mid': ('shared_gs.json', 'gs_w.f32', lambda k: f'gs_{k}')} SIDE = {'den_pos_emb.f32': [1, 8192, 1024], 'dino_rope_cos.f32': [1, 1, 4101, 64], 'dino_rope_sin.f32': [1, 1, 4101, 64], 'gs_perturbation.f32': None} def sha256(path): h = hashlib.sha256() with open(path, 'rb') as f: for block in iter(lambda: f.read(1 << 24), b''): h.update(block) return h.hexdigest() def main(): ap = argparse.ArgumentParser() ap.add_argument('models') ap.add_argument('--dis', default=None) ap.add_argument('--no-sha', action='store_true') ap.add_argument('--precision', choices=['fp16_with_fp32_accum', 'fp16'], default='fp16_with_fp32_accum', help='precision of the GPU graphs') a = ap.parse_args() d = a.models pert = np.load(os.path.join(d, 'gs_perturbation.npy')).astype('