Add a C++/Qt6/CMake CLI prototype that captures the default sink monitor through libpulse and transcribes it in-process with Qwen3-ASR via libllama/libmtmd. Add phase 0/1 verification docs. 新增实时字幕命令行原型:libpulse 采集默认输出 monitor,进程内用 libllama/libmtmd 跑 Qwen3-ASR 推理。附阶段 0/1 验证文档。
49 lines
1.8 KiB
Python
49 lines
1.8 KiB
Python
#!/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)
|