Ai-detector-websterfly / scripts /deploy_hf_space.py
Websterfly's picture
Deploy Websterfly educational AI detection workbench
97799b9 verified
Raw History Blame Contribute Delete
3.69 kB
"""Deploy only Websterfly/Ai-detector-websterfly using a securely configured token.
No GitHub operations, no hardware purchases, no secret values in output.
"""
import argparse,hashlib,json,os,time
from pathlib import Path
from huggingface_hub import HfApi
SPACE='Websterfly/Ai-detector-websterfly'
ROOT=Path(__file__).resolve().parents[1]
def manifest(folder):
files=[]
for path in sorted(folder.rglob('*')):
if not path.is_file() or '__pycache__' in path.parts or path.suffix=='.pyc':continue
rel=path.relative_to(folder)
if path.suffix in ('.safetensors','.incomplete') or '.env' in rel.parts or any(p in ('.git','.cache','.venv','work') for p in rel.parts):raise ValueError('Unsafe deployment path: '+str(rel))
files.append({'path':str(rel),'bytes':path.stat().st_size,'sha256':hashlib.sha256(path.read_bytes()).hexdigest()})
return files
def main():
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--check',action='store_true');parser.add_argument('--wait',action='store_true');args=parser.parse_args()
folder=ROOT/'work/huggingface-upload'
if not folder.exists():raise SystemExit('Build upload directory with scripts/build_hf_space.py first.')
files=manifest(folder)
readme=(folder/'README.md').read_text();dockerfile=(folder/'Dockerfile').read_text()
if 'sdk: docker' not in readme or 'app_port: 7860' not in readme or 'EXPOSE 7860' not in dockerfile:raise SystemExit('Docker/port metadata validation failed.')
token=os.getenv('HF_TOKEN')
print(json.dumps({'target':SPACE,'files':len(files),'bytes':sum(f['bytes'] for f in files),'secure_write_token_configured':bool(token),'remote_written':False},indent=2),flush=True)
(ROOT/'work/huggingface-deployment-manifest.json').write_text(json.dumps({'space':SPACE,'files':files},indent=2))
if args.check:return
if not token:raise SystemExit('Deployment blocked: configure a Space-scoped write token securely as HF_TOKEN in this execution environment. Do not paste the token into chat.')
api=HfApi(token=token)
try:
api.whoami()
before=api.space_info(SPACE)
# Parent guard prevents overwriting an intervening change without review.
commit=api.upload_folder(repo_id=SPACE,repo_type='space',folder_path=str(folder),parent_commit=before.sha,
commit_message='Deploy educational AI detector research workbench using Docker',
ignore_patterns=['**/__pycache__/**','**/*.pyc','**/.env','*.safetensors','**/*.safetensors','**/.cache/**'])
except Exception as exc:
# Keep headers/tokens out of errors; details can be diagnosed without dumping auth.
raise SystemExit('Deployment request failed ('+type(exc).__name__+'). Check token scope and Space access; no credential values printed.')
print(json.dumps({'commit_url':str(commit.commit_url),'space_url':'https://huggingface.co/spaces/'+SPACE,'remote_written':True}),flush=True)
if not args.wait:return
for attempt in range(180):
runtime=api.get_space_runtime(SPACE);stage=str(runtime.stage)
print(json.dumps({'runtime_stage':stage,'poll':attempt+1}),flush=True)
if stage=='RUNNING':
print('Space reports RUNNING. Verify /health, /ready, /workbench and a small real inference before declaring model readiness.',flush=True);return
if any(s in stage for s in ['ERROR','FAILED']):raise SystemExit('Space build/runtime failed; inspect authenticated logs.')
time.sleep(10)
raise SystemExit('Space is still building/starting after the monitoring window. Deployment commit was created; inspect its runtime status.')
if __name__=='__main__':main()