Files

48 lines
1.8 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
"""只抓 GGUF 头部(HTTP Range)读元数据,不下载整个文件。
用法: gguf_head.py <url> [<url> ...]"""
import sys, struct, urllib.request
TYPES = {0:1,1:1,2:2,3:2,4:4,5:4,6:4,7:1,8:None,9:None,10:8,11:8,12:8}
NAMES = {0:"u8",1:"i8",2:"u16",3:"i16",4:"u32",5:"i32",6:"f32",7:"bool",8:"str",9:"arr",10:"u64",11:"i64",12:"f64"}
def readstr(b,o):
n,=struct.unpack_from("<Q",b,o); o+=8
return b[o:o+n].decode("utf-8","replace"), o+n
def peek(url, limit=4_000_000):
req=urllib.request.Request(url, headers={"Range":f"bytes=0-{limit}"})
b=urllib.request.urlopen(req, timeout=60).read()
assert b[:4]==b"GGUF", "not a GGUF"
n_kv,=struct.unpack_from("<Q",b,16); o=24
out={}
for _ in range(n_kv):
k,o=readstr(b,o)
t,=struct.unpack_from("<I",b,o); o+=4
if t==8:
v,o=readstr(b,o)
elif t==9:
et,=struct.unpack_from("<I",b,o); o+=4
n,=struct.unpack_from("<Q",b,o); o+=8
if et==8:
v=[readstr(b,o)[0] for _ in range(min(n,4))]
for _ in range(n): _,o=readstr(b,o)
else:
o+=n*TYPES[et]; v=f"<{n}x{NAMES[et]}>"
else:
sz=TYPES[t]; v=int.from_bytes(b[o:o+sz],"little",signed=t in (1,3,5,11)); o+=sz
out[k]=v
if k=="general.architecture":
break
return out
for url in sys.argv[1:]:
print(f"=== {url.split('/resolve/')[0].split('/')[-2] + '/' + url.split('/')[-1]} ===")
try:
m=peek(url)
print(" architecture =", m.get("general.architecture"), "| name =", m.get("general.name"))
for k,v in m.items():
if "clip" in k or "projector" in k or "audio" in k:
print(f" {k} = {str(v)[:70]}")
except Exception as e:
print(" ERR", e)