onwAMD / flm_verify.py
ryugyosoft's picture
onw AMD 0.1.3: model file check, installer restart, download progress
00a5163 verified
Raw History Blame Contribute Delete
3.31 kB
"""onw AMD test: are a FastFlowLM model's files intact? Checks each file against the hashes in flm's own
model_info.json (sha256 for the big files, git's blob sha1 for the small ones). Standard library only; reads only.
python3 flm_verify.py gemma4-it:12b the copy in onw's model folder
python3 flm_verify.py gemma4-it:12b /path/to/flm another FLM_MODEL_PATH (e.g. Lemonade's, ~/.config/flm)
"""
import glob, hashlib, json, os, sys
WIN = os.name == "nt"
def cfg_dir():
base = os.environ.get("APPDATA") if WIN else os.path.join(os.path.expanduser("~"), ".config")
return os.path.join(base or os.path.expanduser("~"), "onw-amd")
def flm_dir():
exe = "flm.exe" if WIN else "flm"
hits = glob.glob(os.path.join(cfg_dir(), "bin", "flm", "npu", "**", exe), recursive=True)
for d in [os.path.dirname(h) for h in hits] + ["/opt/fastflowlm/share/flm", r"C:\Program Files\flm"]:
if os.path.exists(os.path.join(d, "model_info.json")):
return d
sys.exit("model_info.json not found (install FastFlowLM from the onw window first)")
def models_root(arg):
if arg:
return os.path.expanduser(arg)
try:
d = json.load(open(os.path.join(cfg_dir(), "config.json"), encoding="utf8")).get("models_dir")
except Exception:
d = None
return d or os.path.join(cfg_dir(), "flm")
def digest(path, kind, size):
h = hashlib.sha256() if kind == "sha256" else hashlib.sha1(f"blob {size}\0".encode())
with open(path, "rb") as f:
for b in iter(lambda: f.read(1 << 22), b""):
h.update(b)
return h.hexdigest()
def main():
args = [a for a in sys.argv[1:] if a != "-"]
ck = args[0] if args else "gemma4-it:12b"
d = flm_dir()
family, tag = ck.split(":", 1)
entry = json.load(open(os.path.join(d, "model_list.json"), encoding="utf8"))["models"][family][tag]
info = {f["path"]: f for f in json.load(open(os.path.join(d, "model_info.json"), encoding="utf8"))[ck]}
folder = os.path.join(models_root(args[1] if len(args) > 1 else None), "models", entry["name"])
print("model", ck, "| folder", folder)
bad = 0
for name in entry["files"]:
f, p = info.get(name), os.path.join(folder, name)
if not os.path.exists(p):
print(f" MISSING {name}")
bad += 1
continue
size = os.path.getsize(p)
if f is None:
print(f" ? {name} ({size} bytes; no hash to compare)")
continue
want_size = f.get("size")
kind, want = ("sha256", f["lfs"]["oid"]) if f.get("lfs") else ("sha1", f.get("oid"))
if want_size and size != want_size:
print(f" BAD SIZE {name}: {size} bytes, expected {want_size}")
bad += 1
continue
print(f" ... {name} ({size / 2**20:.0f} MB) hashing", end="\r", flush=True)
got = digest(p, kind, size)
ok = got == want
bad += not ok
print(f" {'OK ' if ok else 'BAD HASH'} {name} ({size / 2**20:.0f} MB){'' if ok else f' {kind} {got[:16]}…, expected {want[:16]}…'}")
print("\nall files intact" if not bad else f"\n{bad} file(s) damaged: download the model again (onw: delete it in the Models tab, then Download)")
if __name__ == "__main__":
main()