openfree commited on
Commit
3fa913e
ยท
verified ยท
1 Parent(s): 54c7c4f

Create repo_to_space_auto.py

Browse files
Files changed (1) hide show
  1. repo_to_space_auto.py +141 -0
repo_to_space_auto.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ repo_to_space_auto.py
4
+ ---------------------
5
+ ๊ณต๊ฐœ Git ๋ ˆํฌ๋ฅผ Hugging Face Gradio Space๋กœ ์ž๋™ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค.
6
+
7
+ ํ•„์š” ํ™˜๊ฒฝ๋ณ€์ˆ˜
8
+ -------------
9
+ BAPI_TOKEN : Brave Search API Key
10
+ FRIENDLI_TOKEN : Friendli Dedicated Endpoint Token
11
+
12
+ CLI ์ธ์ž
13
+ --------
14
+ --repo_url <URL> : ์›๋ณธ Git ๋ ˆํฌ URL (ํ•„์ˆ˜*ยน)
15
+ --hf_token <TOK> : ์“ฐ๊ธฐ ๊ถŒํ•œ Hugging Face Access Token (ํ•„์ˆ˜*ยน)
16
+ --private : ๋น„๊ณต๊ฐœ Space๋กœ ์ƒ์„ฑ
17
+ --hardware <tier> : ์˜ˆ) 't4-medium' GPU ์ธ์Šคํ„ด์Šค ์ง€์ •
18
+
19
+ *ยน ์ธ์ž๋ฅผ ์ƒ๋žตํ•˜๋ฉด ๋™๋ช… ํ™˜๊ฒฝ๋ณ€์ˆ˜(REPO_URL, HF_TOKEN)๊ฐ€ ๋Œ€์‹  ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
20
+ """
21
+
22
+ import os, sys, json, argparse, subprocess, tempfile, textwrap, requests, shutil
23
+ from pathlib import Path
24
+ import git # GitPython
25
+ from huggingface_hub import HfApi, login # HF Hub SDK
26
+
27
+ # ---------- Brave Search ํ—ฌํผ ---------- #
28
+ def brave_search_repo(repo_url: str, count: int = 5) -> list[dict]:
29
+ api_key = os.getenv("BAPI_TOKEN")
30
+ if not api_key:
31
+ raise RuntimeError("ํ™˜๊ฒฝ๋ณ€์ˆ˜ BAPI_TOKEN์ด ์„ค์ •๋ผ ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
32
+ headers = {"X-Subscription-Token": api_key, "Accept": "application/json"}
33
+ params = {"q": f'site:github.com "{repo_url}"', "count": count, "search_lang": "en"}
34
+ resp = requests.get("https://api.search.brave.com/res/v1/web/search",
35
+ headers=headers, params=params, timeout=10)
36
+ resp.raise_for_status()
37
+ return resp.json().get("web", {}).get("results", [])
38
+
39
+ # ---------- Friendli LLM ํ—ฌํผ ---------- #
40
+ def friendli_generate_scaffold(context: str) -> dict:
41
+ token = os.getenv("FRIENDLI_TOKEN")
42
+ if not token:
43
+ raise RuntimeError("ํ™˜๊ฒฝ๋ณ€์ˆ˜ FRIENDLI_TOKEN์ด ์„ค์ •๋ผ ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
44
+ payload = {
45
+ "model": "dep89a2fld32mcm",
46
+ "messages": [
47
+ {"role": "system",
48
+ "content": ("You are an expert Hugging Face Space architect. "
49
+ "Given repository context, output JSON with keys "
50
+ "`app_py`, `requirements_txt`, `need_docker` (bool), "
51
+ "`dockerfile` (if needed) and `summary`.")},
52
+ {"role": "user", "content": context}
53
+ ],
54
+ "max_tokens": 16384,
55
+ "top_p": 0.8,
56
+ "stream": False
57
+ }
58
+ headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
59
+ r = requests.post("https://api.friendli.ai/dedicated/v1/chat/completions",
60
+ json=payload, headers=headers, timeout=120)
61
+ r.raise_for_status()
62
+ return json.loads(r.json()["choices"][0]["message"]["content"])
63
+
64
+ # ---------- ๋ฉ”์ธ ๋ฐฐํฌ ๋กœ์ง ---------- #
65
+ def deploy(repo_url: str, hf_token: str, private=False, hardware=None) -> str:
66
+ """๋ ˆํฌ๋ฅผ Gradio Space๋กœ ๋ฐฐํฌํ•˜๊ณ  Space URL ๋ฐ˜ํ™˜."""
67
+ login(hf_token)
68
+ api = HfApi(token=hf_token)
69
+ user = api.whoami()["name"]
70
+ space = f"{user}/{Path(repo_url).stem.lower().replace('.', '-')}"
71
+ api.create_repo(space, repo_type="space", space_sdk="gradio",
72
+ private=private, exist_ok=True, hardware=hardware)
73
+
74
+ with tempfile.TemporaryDirectory() as work:
75
+ # 1) Brave ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
76
+ brave_meta = brave_search_repo(repo_url)
77
+
78
+ # 2) ์›๋ณธ ๋ ˆํฌ ํด๋ก 
79
+ src = Path(work) / "src"
80
+ git.Repo.clone_from(repo_url, src)
81
+
82
+ readme = ""
83
+ if (src / "README.md").exists():
84
+ readme = (src / "README.md").read_text(encoding="utf-8", errors="ignore")[:4000]
85
+
86
+ tree_out = subprocess.run(["bash", "-lc", f"tree -L 2 {src} | head -n 40"],
87
+ text=True, capture_output=True).stdout
88
+
89
+ context = textwrap.dedent(f"""
90
+ ## Brave meta
91
+ {json.dumps(brave_meta, ensure_ascii=False, indent=2)}
92
+
93
+ ## Repository tree (depth 2)
94
+ {tree_out}
95
+
96
+ ## README (first 4 kB)
97
+ {readme}
98
+ """)
99
+
100
+ # 3) Friendli ์Šค์บํด๋“œ ์ƒ์„ฑ
101
+ scaffold = friendli_generate_scaffold(context)
102
+
103
+ # 4) Space ๋ ˆํฌ ํด๋ก  & ํŒŒ์ผ ์“ฐ๊ธฐ
104
+ dst = Path(work) / "space"
105
+ api.clone_repo(space, local_dir=dst)
106
+
107
+ (dst / "app.py").write_text(scaffold["app_py"], encoding="utf-8")
108
+ (dst / "requirements.txt").write_text(scaffold["requirements_txt"], encoding="utf-8")
109
+ if scaffold.get("need_docker"):
110
+ (dst / "Dockerfile").write_text(scaffold["dockerfile"], encoding="utf-8")
111
+ (dst / "README.md").write_text(scaffold["summary"], encoding="utf-8")
112
+
113
+ subprocess.run(["git", "-C", dst, "add", "."], check=True)
114
+ subprocess.run(["git", "-C", dst, "commit", "-m", "Initial auto-deploy"], check=True)
115
+ subprocess.run(["git", "-C", dst, "push"], check=True)
116
+
117
+ return f"https://huggingface.co/spaces/{space}"
118
+
119
+ # ---------- CLI ์—”ํŠธ๋ฆฌ ---------- #
120
+ def main():
121
+ parser = argparse.ArgumentParser(description="Git ๋ ˆํฌ๋ฅผ Hugging Face Gradio Space๋กœ ์ž๋™ ๋ฐฐํฌ")
122
+ parser.add_argument("--repo_url", default=os.getenv("REPO_URL"),
123
+ help="์›๋ณธ Git ๋ ˆํฌ์ง€ํ† ๋ฆฌ URL (or env REPO_URL)")
124
+ parser.add_argument("--hf_token", default=os.getenv("HF_TOKEN"),
125
+ help="์“ฐ๊ธฐ ๊ถŒํ•œ HF ํ† ํฐ (or env HF_TOKEN)")
126
+ parser.add_argument("--private", action="store_true", help="๋น„๊ณต๊ฐœ Space ์ƒ์„ฑ")
127
+ parser.add_argument("--hardware", default=None, help="์˜ˆ: 't4-medium'")
128
+ args = parser.parse_args()
129
+
130
+ if not args.repo_url or not args.hf_token:
131
+ parser.error("--repo_url ๋ฐ --hf_token (๋˜๋Š” ๋™๋ช… ํ™˜๊ฒฝ๋ณ€์ˆ˜) ๋‘˜ ๋‹ค ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.")
132
+
133
+ try:
134
+ url = deploy(args.repo_url, args.hf_token, args.private, args.hardware)
135
+ print(f"โœ… ๋ฐฐํฌ ์„ฑ๊ณต: {url}")
136
+ except Exception as e:
137
+ print(f"โŒ ๋ฐฐํฌ ์‹คํŒจ: {e}", file=sys.stderr)
138
+ sys.exit(1)
139
+
140
+ if __name__ == "__main__":
141
+ main()