File size: 4,678 Bytes
6fe13ea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
149
"""
Stage and deploy Workflow1111 to a Hugging Face Space.

    python apps/05_workflow1111/deploy_space.py --stage     # build staging dir only
    python apps/05_workflow1111/deploy_space.py --push      # create + upload

The Space must be **public**: the reference-node sample images are referenced by
their public `.../resolve/main/samples/...` URL, which is the only default shape
the canvas renders *and* a remote inference provider can fetch. A private Space
would serve 401s for those URLs and the defaults would come up blank.

OAuth is enabled in the README frontmatter, so each visitor signs in and their
own token pays for their own inference — the Space ships no token of its own.
"""

import argparse
import os
import shutil
import sys

HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.abspath(os.path.join(HERE, "..", ".."))
STAGE = os.path.join(HERE, "_space")

SPACE_ID = os.environ.get("WORKFLOW1111_SPACE", "ysharma/Workflow1111")

SHIP = [
    "test_api.py",
    "deploy_space.py",
    "app.py",
    "nodes.py",
    "workflow.json",
    "requirements.txt",
    "build_workflow.py",
    "layout.json",
    "make_samples.py",
    "test_nodes.py",
    "test_pipelines.py",
]

FRONTMATTER = """---
title: Workflow1111 Diffusion Studio
emoji: 🎨
colorFrom: indigo
colorTo: purple
sdk: gradio
sdk_version: 6.22.0
app_file: app.py
pinned: false
license: mit
hf_oauth: true
hf_oauth_scopes:
  - inference-api
short_description: Automatic1111-style studio on one gr.Workflow canvas
---

> **Sign in with Hugging Face** (button at the top right) before running
> anything. This Space carries no token of its own — every `model`, `space` and
> inference-calling `fn` node runs on *your* token and your own inference quota.

"""


def read_token():
    for path in (os.path.join(ROOT, "hf-write-token.txt"),):
        if os.path.exists(path):
            with open(path, encoding="utf-8") as f:
                tok = f.read().strip()
            if tok:
                return tok
    tok = os.environ.get("HF_TOKEN")
    if tok:
        return tok
    raise SystemExit("No write token found (hf-write-token.txt or HF_TOKEN).")


def stage():
    if os.path.exists(STAGE):
        shutil.rmtree(STAGE)
    os.makedirs(STAGE)

    for name in SHIP:
        src = os.path.join(HERE, name)
        if not os.path.exists(src):
            raise SystemExit(f"missing file to ship: {name}")
        shutil.copy2(src, os.path.join(STAGE, name))

    samples_src = os.path.join(HERE, "samples")
    samples_dst = os.path.join(STAGE, "samples")
    os.makedirs(samples_dst)
    for name in sorted(os.listdir(samples_src)):
        if name.startswith("_"):
            continue
        shutil.copy2(os.path.join(samples_src, name), os.path.join(samples_dst, name))

    with open(os.path.join(HERE, "README.md"), encoding="utf-8") as f:
        body = f.read()
    with open(os.path.join(STAGE, "README.md"), "w", encoding="utf-8") as f:
        f.write(FRONTMATTER + body)

    # Nothing secret may ever reach the Space.
    for dirpath, _dirs, files in os.walk(STAGE):
        for name in files:
            low = name.lower()
            if "token" in low and low.endswith(".txt"):
                raise SystemExit(f"refusing to ship {name}")

    total = sum(os.path.getsize(os.path.join(d, f))
                for d, _s, fs in os.walk(STAGE) for f in fs)
    files = [os.path.relpath(os.path.join(d, f), STAGE)
             for d, _s, fs in os.walk(STAGE) for f in fs]
    print(f"staged {len(files)} files ({total // 1024} KB) in {os.path.relpath(STAGE, os.getcwd())}")
    for f in sorted(files):
        size = os.path.getsize(os.path.join(STAGE, f)) // 1024
        print(f"   {f:34} {size:>5} KB")
    return files


def push():
    from huggingface_hub import HfApi

    api = HfApi(token=read_token())
    who = api.whoami()
    print(f"authenticated as: {who.get('name')}")

    url = api.create_repo(repo_id=SPACE_ID, repo_type="space", space_sdk="gradio",
                          exist_ok=True, private=False)
    print(f"space repo ready: {url}")

    api.upload_folder(
        folder_path=STAGE,
        repo_id=SPACE_ID,
        repo_type="space",
        commit_message="Workflow1111 — Automatic1111-style diffusion studio on gr.Workflow",
    )
    print(f"uploaded → https://huggingface.co/spaces/{SPACE_ID}")


if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("--stage", action="store_true")
    ap.add_argument("--push", action="store_true")
    args = ap.parse_args()
    if not (args.stage or args.push):
        ap.error("pass --stage or --push")
    stage()
    if args.push:
        push()