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

Update app.py

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