askmydocs / scripts /hf_state_backup.py
Prabu17's picture
Upload folder using huggingface_hub
f8b48da verified
Raw History Blame Contribute Delete
3.53 kB
"""Back up AskMyDocs state to a Hugging Face Storage Bucket.
Creates a compressed archive of PostgreSQL data, Qdrant storage, and uploaded
documents, then uploads it to the specified HF Storage Bucket. The Space's
``start.sh`` restores this archive on boot when ``RESTORE_ON_BOOT=true``.
Usage:
python scripts/hf_state_backup.py --bucket username/askmydocs-data
python scripts/hf_state_backup.py --bucket username/askmydocs-data --data-root /home/user
"""
from __future__ import annotations
import argparse
import subprocess
import tempfile
from pathlib import Path
def create_archive(data_root: Path, output: Path) -> bool:
"""Create a zstd-compressed tar of the state directories."""
dirs_to_include = ["pgdata", "qdrant_storage"]
uploads_dir = data_root / "app" / "data" / "uploads"
if uploads_dir.exists():
dirs_to_include.append("app/data/uploads")
existing = [d for d in dirs_to_include if (data_root / d).exists()]
if not existing:
print("No state directories found to back up.")
return False
cmd = [
"tar",
"--zstd",
"-cf",
str(output),
"-C",
str(data_root),
*existing,
]
print(f"Creating archive: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"tar failed: {result.stderr}")
return False
size_mb = output.stat().st_size / (1024 * 1024)
print(f"Archive created: {output} ({size_mb:.1f} MB)")
return True
def upload_to_bucket(archive: Path, bucket: str, token: str | None = None) -> bool:
"""Upload the archive to an HF Storage Bucket.
Storage Buckets are not repos: ``upload_file(repo_type="space_storage")``
does not exist (supported repo types are model/dataset/space). The bucket
API is ``batch_bucket_files(bucket_id=..., add=[(local, remote)])``.
"""
try:
from huggingface_hub import batch_bucket_files
except ImportError:
print("Error: huggingface_hub is required. Install with: pip install huggingface_hub")
return False
print(f"Uploading {archive.name} to bucket {bucket}...")
batch_bucket_files(
bucket_id=bucket,
add=[(archive, "state.tar.zst")],
token=token,
)
print(f"Uploaded to hf://buckets/{bucket}/state.tar.zst")
return True
def main() -> int:
parser = argparse.ArgumentParser(description="Back up AskMyDocs state to HF Storage Bucket.")
parser.add_argument(
"--bucket",
required=True,
help="HF Storage Bucket name (e.g. 'username/askmydocs-data')",
)
parser.add_argument(
"--data-root",
type=Path,
default=Path("/home/user"),
help="Data root directory (default: /home/user for HF Space)",
)
parser.add_argument(
"--token",
default=None,
help="HF token for private bucket access (default: HF_TOKEN env var)",
)
args = parser.parse_args()
import os
token = args.token or os.environ.get("HF_TOKEN")
with tempfile.NamedTemporaryFile(suffix=".tar.zst", delete=False) as tmp:
tmp_path = Path(tmp.name)
try:
if not create_archive(args.data_root, tmp_path):
return 1
if not upload_to_bucket(tmp_path, args.bucket, token):
return 1
finally:
tmp_path.unlink(missing_ok=True)
print("State backup complete.")
return 0
if __name__ == "__main__":
raise SystemExit(main())