"""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()