File size: 4,465 Bytes
28fcede
 
 
 
 
 
 
 
 
 
 
 
 
5c16879
28fcede
 
 
 
 
 
a8ed61e
28fcede
 
 
 
 
 
 
ada0795
28fcede
 
 
 
 
 
 
 
 
 
 
 
 
 
5c16879
28fcede
 
61c1dd0
28fcede
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f8018a0
28fcede
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c62098c
28fcede
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a0502d2
 
28fcede
 
 
f8018a0
28fcede
5c16879
28fcede
 
 
 
 
 
 
 
 
 
a0502d2
 
28fcede
 
 
 
 
ada0795
28fcede
 
61c1dd0
28fcede
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""Create or update the official Hugging Face Space without exposing secrets."""

from __future__ import annotations

import argparse
import os
from pathlib import Path

from dotenv import load_dotenv
from huggingface_hub import HfApi

ROOT = Path(__file__).resolve().parents[1]
SPACE_ID = "build-small-hackathon/persona-capsule"
SPACE_HOST = "build-small-hackathon-persona-capsule.hf.space"
IGNORED = [
    ".env",
    ".env.*",
    ".git/**",
    ".github/**",
    ".modal/**",
    ".persona-capsule-data/**",
    "**/.persona-capsule-data/**",
    ".pytest_cache/**",
    ".ruff_cache/**",
    ".venv/**",
    "**/__pycache__/**",
    "artifacts/**",
    "checkpoints/**",
    "docs/**",
    "outputs/**",
]


def _required(name: str) -> str:
    value = os.environ.get(name, "").strip()
    if not value:
        raise SystemExit(f"Missing required environment variable: {name}")
    return value


def deployment_plan() -> dict[str, object]:
    return {
        "space_id": SPACE_ID,
        "public_base_url": f"https://{SPACE_HOST}",
        "visibility": "public",
        "sdk": "gradio",
        "hardware": "cpu-basic",
        "oauth": True,
        "secret_names": [
            "HF_TOKEN",
            "MODAL_TOKEN_ID",
            "MODAL_TOKEN_SECRET",
        ],
        "variable_names": [
            "APP_ENV",
            "ENABLE_BATTLE",
            "ENABLE_CARD",
            "ENABLE_CREATION",
            "ENABLE_DEEP_TRAINING",
            "ENABLE_FUSION",
            "ENABLE_STEERING",
            "ENABLE_VOICE",
            "GRADIO_SSR_MODE",
            "HF_CAPSULE_REPO_ID",
            "PUBLIC_BASE_URL",
        ],
    }


def deploy(*, dry_run: bool) -> None:
    load_dotenv(ROOT / ".env")
    plan = deployment_plan()
    if dry_run:
        for key, value in plan.items():
            print(f"{key}: {value}")
        return

    if os.environ.get("CONFIRM_CREDENTIALS_ROTATED", "").casefold() != "true":
        raise SystemExit(
            "Deployment refused. Rotate exposed credentials, then set "
            "CONFIRM_CREDENTIALS_ROTATED=true."
        )

    deploy_token = _required("HF_TOKEN")
    service_token = os.environ.get("SPACE_HF_SERVICE_TOKEN", "").strip() or deploy_token
    api = HfApi(token=deploy_token)
    owner = str(api.whoami()["name"])
    data_repo = os.environ.get(
        "HF_CAPSULE_REPO_ID",
        f"{owner}/persona-capsule-private-data",
    ).strip()
    api.create_repo(
        repo_id=data_repo,
        repo_type="dataset",
        private=True,
        exist_ok=True,
    )
    api.create_repo(
        repo_id=SPACE_ID,
        repo_type="space",
        private=False,
        exist_ok=True,
        space_sdk="gradio",
    )

    variables = {
        "APP_ENV": "production",
        "ENABLE_BATTLE": os.environ.get("ENABLE_BATTLE", "true"),
        "ENABLE_CARD": os.environ.get("ENABLE_CARD", "true"),
        "ENABLE_CREATION": os.environ.get("ENABLE_CREATION", "true"),
        # Keep the judged Space focused on the live, working inference path.
        "ENABLE_DEEP_TRAINING": "false",
        "ENABLE_FUSION": os.environ.get("ENABLE_FUSION", "true"),
        "ENABLE_STEERING": os.environ.get("ENABLE_STEERING", "true"),
        "ENABLE_VOICE": os.environ.get("ENABLE_VOICE", "true"),
        "GRADIO_SSR_MODE": "false",
        "HF_CAPSULE_REPO_ID": data_repo,
        "PUBLIC_BASE_URL": f"https://{SPACE_HOST}",
    }
    secrets = {
        "HF_TOKEN": service_token,
        "MODAL_TOKEN_ID": _required("MODAL_TOKEN_ID"),
        "MODAL_TOKEN_SECRET": _required("MODAL_TOKEN_SECRET"),
    }
    for key, value in variables.items():
        api.add_space_variable(SPACE_ID, key, value)
    for key, value in secrets.items():
        api.add_space_secret(SPACE_ID, key, value)
    if "ELEVENLABS_API_KEY" in api.get_space_secrets(SPACE_ID):
        api.delete_space_secret(SPACE_ID, "ELEVENLABS_API_KEY")
    commit = api.upload_folder(
        repo_id=SPACE_ID,
        repo_type="space",
        folder_path=ROOT,
        ignore_patterns=IGNORED,
        delete_patterns=["docs/**"],
        commit_message="Deploy Persona Capsule hackathon Space",
    )
    api.request_space_hardware(SPACE_ID, "cpu-basic")
    print(f"Deployed {SPACE_ID} at commit {commit.oid}.")


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--dry-run", action="store_true")
    arguments = parser.parse_args()
    deploy(dry_run=arguments.dry_run)