Corp_AI_Auditor / scripts /deploy_hf.py
minato1718's picture
Sync Space with repo and remove stale files
7cf7aa9 verified
"""Deploy AuditEnv to HuggingFace Spaces — full sync with stale-file cleanup."""
from huggingface_hub import HfApi, CommitOperationAdd, CommitOperationDelete
import os
REPO_ID = "minato1718/Corp_AI_Auditor"
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# --- Inline file contents for critical config files ---
DOCKERFILE = """\
FROM python:3.11-slim
WORKDIR /app
COPY requirements.runtime.txt ./
RUN pip install --no-cache-dir -r requirements.runtime.txt
COPY src ./src
COPY configs ./configs
COPY openenv.yaml ./openenv.yaml
COPY inference.py ./inference.py
COPY scripts ./scripts
COPY server ./server
COPY app.py ./app.py
RUN mkdir -p data
EXPOSE 7860
CMD ["uvicorn", "auditenv.server:app", "--host", "0.0.0.0", "--port", "7860", "--app-dir", "src"]
"""
REQUIREMENTS_RUNTIME = """\
fastapi>=0.115.0
uvicorn>=0.30.0
pydantic>=2.7.0
pyyaml>=6.0.1
gradio>=4.44.0
requests>=2.32.0
httpx>=0.27.0
openai>=1.51.0
"""
README_HF = """\
---
title: AuditEnv - OpenEnv Agentic Environment
emoji: 🏢
colorFrom: indigo
colorTo: purple
sdk: docker
app_port: 7860
pinned: false
license: mit
---
# 🏢 AuditEnv — OpenEnv Agentic Environment
Autonomous compliance auditing powered by reinforcement learning.
"""
SKIP = {"__pycache__", ".pyc", ".egg-info", ".venv", ".git",
"artifacts", ".pytest_cache", ".env"}
def should_skip(path):
parts = path.replace("\\", "/").split("/")
return any(s in parts or any(p.endswith(s) for p in parts) for s in SKIP)
def collect_dir(local_dir, repo_prefix):
ops = []
paths = set()
for dp, dns, fns in os.walk(local_dir):
dns[:] = [d for d in dns if d not in SKIP]
for f in fns:
fp = os.path.join(dp, f)
if should_skip(fp):
continue
rel = os.path.relpath(fp, ROOT).replace("\\", "/")
ops.append(CommitOperationAdd(path_in_repo=rel, path_or_fileobj=fp))
paths.add(rel)
return ops, paths
def main():
api = HfApi()
add_ops = []
desired_paths = set()
def add_inline(path_in_repo: str, payload: bytes):
add_ops.append(CommitOperationAdd(path_in_repo=path_in_repo, path_or_fileobj=payload))
desired_paths.add(path_in_repo)
def add_local(path_in_repo: str, abs_path: str):
add_ops.append(CommitOperationAdd(path_in_repo=path_in_repo, path_or_fileobj=abs_path))
desired_paths.add(path_in_repo)
# Inline overrides
add_inline("Dockerfile", DOCKERFILE.encode())
add_inline("requirements.runtime.txt", REQUIREMENTS_RUNTIME.encode())
add_inline("README.md", README_HF.encode())
# Local files
for f in ["openenv.yaml", "inference.py", "app.py", "pyproject.toml", "uv.lock"]:
fp = os.path.join(ROOT, f)
if os.path.isfile(fp):
add_local(f, fp)
# Directories
for d in ["src", "configs", "scripts", "server"]:
dp = os.path.join(ROOT, d)
if os.path.isdir(dp):
dir_ops, dir_paths = collect_dir(dp, d)
add_ops.extend(dir_ops)
desired_paths.update(dir_paths)
# Remove files in Space repo that are no longer part of the deploy set.
remote_files = set(api.list_repo_files(repo_id=REPO_ID, repo_type="space"))
protected = {".gitattributes"}
delete_paths = sorted(
path for path in remote_files if path not in desired_paths and path not in protected
)
delete_ops = [CommitOperationDelete(path_in_repo=path) for path in delete_paths]
ops = delete_ops + add_ops
print(f"[*] Syncing Space {REPO_ID}...")
print(f" Add/Update: {len(add_ops)} files")
print(f" Delete: {len(delete_ops)} stale files")
api.create_commit(
repo_id=REPO_ID,
repo_type="space",
operations=ops,
commit_message="Sync Space with repo and remove stale files",
)
print(f"[✓] Done! https://huggingface.co/spaces/{REPO_ID}")
if __name__ == "__main__":
main()