PhillNet_Recall / scripts /publish_hf.py
ayjays132's picture
Upload 121 files
3b3b2bd verified
Raw History Blame Contribute Delete
3.35 kB
"""Manifest-verified, new-repository-only HF upload. Dry run unless --publish.
Use `hf auth login` locally. Never place tokens in a card or a command argument.
A model repository and its synthetic demo Space are distinct publish targets.
"""
from pathlib import Path
import argparse,hashlib,json,re,sys
ROOT=Path(__file__).resolve().parents[1]
DENY=('.sqlite','.sqlite3','.db','.env','.pem','.key','.db-wal','.db-shm','.sqlite3-wal','.sqlite3-shm')
def release_files(root=ROOT):
root=Path(root).resolve();manifest=json.loads((root/'release_manifest.json').read_text());paths=[];seen=set()
for item in manifest['files']:
name=item['path'];p=root/name
if name in seen:raise ValueError('duplicate manifest path')
seen.add(name)
if '\\' in name or name.startswith('/') or '..' in Path(name).parts or p.is_symlink() or not p.resolve().is_relative_to(root):raise ValueError('unsafe release path')
if name.lower().endswith(DENY) or any(x.startswith('.') and x not in ('.github','.dockerignore','.gitignore','.keep','.gitattributes') for x in Path(name).parts):raise ValueError('private or unexpected path in manifest')
raw=p.read_bytes()
if len(raw)!=item['bytes'] or hashlib.sha256(raw).hexdigest()!=item['sha256']:raise ValueError(f'changed release file: {name}')
paths.append(p)
return paths+[root/'release_manifest.json']
def main():
p=argparse.ArgumentParser();p.add_argument('--repo',default=None);p.add_argument('--target',choices=['model','space'],default='model')
p.add_argument('--space-dir',type=Path,default=ROOT.parent/'PhillNet-Recall-Space')
p.add_argument('--publish',action='store_true');p.add_argument('--public',action='store_true')
a=p.parse_args();root=ROOT if a.target=='model' else a.space_dir.resolve()
repo=a.repo or ('ayjays132/PhillNet-Recall' if a.target=='model' else 'ayjays132/PhillNet-Recall-Demo')
if not re.fullmatch(r'[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+',repo):raise ValueError('repository must be owner/name')
paths=release_files(root);manifest=json.loads((root/'release_manifest.json').read_text());version=manifest.get('version','unknown')
print(json.dumps({'repo':repo,'target':a.target,'version':version,'files':len(paths),'bytes':sum(f.stat().st_size for f in paths),
'visibility':'public' if a.public else 'private','action':'publish' if a.publish else 'dry_run'},indent=2))
if not a.publish:return 0
from huggingface_hub import HfApi,CommitOperationAdd
api=HfApi();account=api.whoami()
if account.get('name')!=repo.split('/')[0]:raise RuntimeError('logged-in account does not own the requested personal namespace')
kwargs={'repo_type':a.target,'private':not a.public,'exist_ok':False}
if a.target=='space':kwargs['space_sdk']='docker'
# Existing repositories are never overwritten and their audience is unchanged.
api.create_repo(repo,**kwargs)
info=api.create_commit(repo,repo_type=a.target,commit_message=f'PhillNet Recall {version}: verified release',
operations=[CommitOperationAdd(path_in_repo=str(f.relative_to(root)),path_or_fileobj=str(f)) for f in paths])
print(json.dumps({'repo':repo,'commit':info.oid,'commit_url':info.commit_url,'uploaded_files':len(paths)}))
return 0
if __name__=='__main__':raise SystemExit(main())