openfree commited on
Commit
210a986
ยท
verified ยท
1 Parent(s): 9297033

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +509 -204
app.py CHANGED
@@ -1,266 +1,571 @@
1
- import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
2
  import os
3
  import sys
 
 
 
 
 
 
 
4
  from pathlib import Path
 
5
 
6
- # repo_to_space_auto ๋ชจ๋“ˆ ๋™์  ์ž„ํฌํŠธ
7
- sys.path.insert(0, str(Path(__file__).parent))
8
- from repo_to_space_auto import deploy
9
 
10
- # OAuth ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ
11
- OAUTH_ENABLED = os.getenv("OAUTH_CLIENT_ID") is not None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- def launch_deploy_oauth(repo_url, private, profile: gr.OAuthProfile | None):
14
- """OAuth ์ธ์ฆ ๋ฒ„์ „"""
15
- if not profile:
16
- return """### โŒ ๋กœ๊ทธ์ธ ํ•„์š”
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- ์ƒ๋‹จ์˜ 'Sign in with Hugging Face' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
- hf_token = profile.token
 
 
 
 
 
 
 
21
 
22
- # ํ† ํฐ ์ •๋ฆฌ (OAuth์—์„œ๋„ ์•ˆ์ „ํ•˜๊ฒŒ)
23
- if hf_token:
24
- hf_token = hf_token.strip()
 
 
 
 
25
 
26
- return _deploy_space(repo_url, hf_token, private)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- def launch_deploy_manual(repo_url, hf_token, private):
29
- """์ˆ˜๋™ ํ† ํฐ ์ž…๋ ฅ ๋ฒ„์ „"""
30
- if not hf_token:
31
- return """### โŒ ํ† ํฐ ํ•„์š”
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
- Hugging Face Write ํ† ํฐ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- # ํ† ํฐ ์ •๋ฆฌ (๊ณต๋ฐฑ, ์ค„๋ฐ”๊ฟˆ ์ œ๊ฑฐ)
36
- hf_token = hf_token.strip()
 
 
37
 
38
- # ํ† ํฐ ํ˜•์‹ ๊ฒ€์ฆ
39
- if not hf_token.startswith("hf_"):
40
- return """### โŒ ์ž˜๋ชป๋œ ํ† ํฐ ํ˜•์‹
 
 
 
41
 
42
- ํ† ํฐ์€ 'hf_'๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
43
- https://huggingface.co/settings/tokens ์—์„œ Write ๊ถŒํ•œ ํ† ํฐ์„ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”."""
 
44
 
45
- return _deploy_space(repo_url, hf_token, private)
46
-
47
- def _deploy_space(repo_url, hf_token, private):
48
- """๊ณตํ†ต ๋ฐฐํฌ ๋กœ์ง"""
49
- # URL ์ •๋ฆฌ
50
  repo_url = repo_url.strip()
 
 
51
 
52
- # URL ๊ฒ€์ฆ
53
- if not repo_url.startswith(("https://github.com/", "http://github.com/", "[email protected]:")):
54
- return """### โŒ ์ž˜๋ชป๋œ Repository URL
55
 
56
- GitHub URL ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
57
- ์˜ˆ์‹œ: https://github.com/username/repository"""
58
 
59
- # ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋Œ€์‹  ์ง์ ‘ ํ† ํฐ ์ „๋‹ฌ
60
  try:
61
- link = deploy(repo_url, hf_token, private=private)
62
- return f"""### โœ… Space ์ƒ์„ฑ ์™„๋ฃŒ
63
 
64
  ๐ŸŽ‰ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฐฐํฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!
65
 
66
- **Space URL:** [{link}]({link})
 
 
 
 
 
 
67
 
68
  ---
69
- *๋ฐฐํฌ๋œ Space๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด์„ธ์š”.*"""
 
70
  except Exception as e:
71
  error_msg = str(e)
72
 
73
- # ํŠน์ • ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์ƒ์„ธ ์•ˆ๋‚ด
74
  if "BAPI_TOKEN" in error_msg:
75
  return """### โŒ Brave Search API ํ† ํฐ ํ•„์š”
76
 
77
- Space Settings > Variables and secrets์—์„œ `BAPI_TOKEN`์„ ์„ค์ •ํ•ด์ฃผ์„ธ์š”.
78
- [Brave Search API](https://brave.com/search/api/) ์—์„œ ๋ฌด๋ฃŒ ํ‚ค๋ฅผ ๋ฐœ๊ธ‰๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."""
 
 
 
 
79
  elif "FRIENDLI_TOKEN" in error_msg:
80
  return """### โŒ Friendli AI ํ† ํฐ ํ•„์š”
81
 
82
- Space Settings > Variables and secrets์—์„œ `FRIENDLI_TOKEN`์„ ์„ค์ •ํ•ด์ฃผ์„ธ์š”.
83
- [Friendli AI](https://friendli.ai/) ์—์„œ API ํ‚ค๋ฅผ ๋ฐœ๊ธ‰๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."""
84
- elif "Invalid header value" in error_msg:
85
- return """### โŒ ํ† ํฐ ์˜ค๋ฅ˜
86
-
87
- ํ† ํฐ์— ์ž˜๋ชป๋œ ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
88
- ํ† ํฐ์„ ๋‹ค์‹œ ๋ณต์‚ฌํ•˜์—ฌ ๊ณต๋ฐฑ์ด๋‚˜ ์ค„๋ฐ”๊ฟˆ ์—†์ด ๋ถ™์—ฌ๋„ฃ์–ด์ฃผ์„ธ์š”."""
89
- elif "401" in error_msg or "403" in error_msg:
90
  return """### โŒ ์ธ์ฆ ์‹คํŒจ
91
 
92
- ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ Write ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.
93
- https://huggingface.co/settings/tokens ์—์„œ Write ๊ถŒํ•œ์ด ์žˆ๋Š” ํ† ํฐ์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”."""
 
 
 
 
94
  else:
95
  return f"""### โŒ ๋ฐฐํฌ ์˜ค๋ฅ˜
96
 
97
- ์˜ค๋ฅ˜ ๋‚ด์šฉ: `{error_msg}`
 
 
 
98
 
99
- **๊ฐ€๋Šฅํ•œ ์›์ธ:**
100
- - ์ž˜๋ชป๋œ Repository URL
101
- - ๊ถŒํ•œ ๋ถ€์กฑ (write ๊ถŒํ•œ ํ•„์š”)
102
- - ๋„คํŠธ์›Œํฌ ๋ฌธ์ œ"""
 
103
 
104
- # Gradio ์•ฑ ๊ตฌ์„ฑ
105
- with gr.Blocks(
106
- title="HF Space Auto-Deployer",
107
- theme=gr.themes.Soft(),
108
- css="""
109
- .main-container { max-width: 800px; margin: 0 auto; }
110
- .gr-button-primary { background-color: #2563eb !important; }
111
- .status-box { padding: 20px; border-radius: 8px; margin-top: 20px; }
112
- """
113
- ) as demo:
114
- gr.Markdown("""
115
- # ๐Ÿš€ Git Repository โ†’ Hugging Face Space ์ž๋™ ๋ฐฐํฌ
116
-
117
- ๊ณต๊ฐœ Git ์ €์žฅ์†Œ๋ฅผ Hugging Face Gradio Space๋กœ ์ž๋™ ๋ณ€ํ™˜ํ•˜๊ณ  ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค.
118
-
119
- ## ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
120
- 1. **์ธ์ฆ**: OAuth ๋กœ๊ทธ์ธ ๋˜๋Š” ํ† ํฐ ์ž…๋ ฅ
121
- 2. **Repository URL ์ž…๋ ฅ**
122
- 3. **Deploy ๋ฒ„ํŠผ ํด๋ฆญ**
123
-
124
- ---
125
- """)
126
-
127
- with gr.Column(elem_classes="main-container"):
128
- if OAUTH_ENABLED:
129
- # OAuth ๋ฒ„์ „
130
- gr.LoginButton(
131
- value="Sign in with Hugging Face ๐Ÿค—",
132
- variant="primary",
133
- size="lg"
134
- )
135
-
136
- gr.Markdown("### ๐Ÿ“ ๋ฐฐํฌ ์„ค์ •")
137
-
138
- repo_input = gr.Textbox(
139
- label="Git Repository URL",
140
- placeholder="https://github.com/username/repository",
141
- info="๊ณต๊ฐœ ์ €์žฅ์†Œ URL์„ ์ž…๋ ฅํ•˜์„ธ์š”"
142
- )
143
-
144
- private_checkbox = gr.Checkbox(
145
- label="๐Ÿ”’ Private Space๋กœ ์ƒ์„ฑ",
146
- value=False,
147
- info="์ฒดํฌํ•˜๋ฉด ๋น„๊ณต๊ฐœ Space๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค"
148
- )
149
-
150
- deploy_btn = gr.Button(
151
- "๐Ÿš€ Deploy to Space",
152
- variant="primary",
153
- size="lg"
154
- )
155
-
156
- output_status = gr.Markdown(
157
- elem_classes="status-box",
158
- visible=False
159
- )
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
- # OAuth ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
162
- deploy_btn.click(
163
- fn=launch_deploy_oauth,
164
- inputs=[repo_input, private_checkbox],
165
- outputs=output_status
166
- ).then(
167
- fn=lambda: gr.update(visible=True),
168
- outputs=output_status
169
- )
170
- else:
171
- # ์ˆ˜๋™ ํ† ํฐ ์ž…๋ ฅ ๋ฒ„์ „
172
  gr.Markdown("""
173
- ### ๐Ÿ” ์ธ์ฆ ์ •๋ณด
174
-
175
- > **์ฐธ๊ณ **: OAuth๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์€ Space์ž…๋‹ˆ๋‹ค.
176
- > Space ์„ค์ •์—์„œ `hf_oauth: true`๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์ž๋™ ๋กœ๊ทธ์ธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
 
177
  """)
178
 
179
- token_input = gr.Textbox(
180
- label="Hugging Face Write Token",
181
- type="password",
182
- placeholder="hf_xxxxxxxxxxxxxxxxxxxxx",
183
- info="https://huggingface.co/settings/tokens ์—์„œ Write ๊ถŒํ•œ ํ† ํฐ ์ƒ์„ฑ"
184
- )
185
-
186
- gr.Markdown("### ๐Ÿ“ ๋ฐฐํฌ ์„ค์ •")
187
-
188
- repo_input = gr.Textbox(
189
- label="Git Repository URL",
190
- placeholder="https://github.com/username/repository",
191
- info="๊ณต๊ฐœ ์ €์žฅ์†Œ URL์„ ์ž…๋ ฅํ•˜์„ธ์š”"
192
- )
193
-
194
- private_checkbox = gr.Checkbox(
195
- label="๐Ÿ”’ Private Space๋กœ ์ƒ์„ฑ",
196
- value=False,
197
- info="์ฒดํฌํ•˜๋ฉด ๋น„๊ณต๊ฐœ Space๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค"
198
- )
199
 
 
200
  deploy_btn = gr.Button(
201
- "๐Ÿš€ Deploy to Space",
202
  variant="primary",
203
  size="lg"
204
  )
205
 
 
206
  output_status = gr.Markdown(
207
  elem_classes="status-box",
208
  visible=False
209
  )
210
 
211
- # ์ˆ˜๋™ ์ž…๋ ฅ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
212
- deploy_btn.click(
213
- fn=launch_deploy_manual,
214
- inputs=[repo_input, token_input, private_checkbox],
215
- outputs=output_status
216
- ).then(
217
- fn=lambda: gr.update(visible=True),
218
- outputs=output_status
219
- )
220
-
221
- # ๊ณตํ†ต ์˜ˆ์‹œ ๋ฐ ๋„์›€๋ง
222
- gr.Markdown("""
223
- ### ๐Ÿ’ก ์˜ˆ์‹œ
224
- - `https://github.com/gradio-app/gradio`
225
- - `https://github.com/huggingface/transformers`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
- ### โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ
228
- - **ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํ•„์š”**: `BAPI_TOKEN` (Brave Search API), `FRIENDLI_TOKEN` (Friendli AI)
229
- - Space ์ด๋ฆ„์€ repository ์ด๋ฆ„์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค
230
- - GPU๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ Space ์ƒ์„ฑ ํ›„ ์ˆ˜๋™ ์„ค์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค
231
- """)
 
 
 
 
 
 
232
 
233
- if __name__ == "__main__":
234
- # ์‹œ์ž‘ ์‹œ ํ™˜๊ฒฝ ์ฒดํฌ
235
- print("\n" + "="*50)
236
- print("๐Ÿš€ HF Space Auto-Deployer ์‹œ์ž‘")
237
- print("="*50)
 
 
 
 
238
 
239
- # ํ•„์ˆ˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ฒดํฌ
240
- missing_vars = []
241
- if not os.getenv("BAPI_TOKEN"):
242
- missing_vars.append("BAPI_TOKEN (Brave Search API)")
243
- if not os.getenv("FRIENDLI_TOKEN"):
244
- missing_vars.append("FRIENDLI_TOKEN (Friendli AI)")
245
 
246
- if missing_vars:
247
- print("\nโš ๏ธ ๋‹ค์Œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค:")
248
- for var in missing_vars:
249
- print(f" - {var}")
250
- print("\nSpace Settings > Variables and secrets์—์„œ ์„ค์ •ํ•ด์ฃผ์„ธ์š”.")
 
 
 
 
251
  else:
252
- print("โœ… ๋ชจ๋“  ํ•„์ˆ˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
253
-
254
- # OAuth ์ƒํƒœ ํ™•์ธ
255
- if OAUTH_ENABLED:
256
- print("โœ… OAuth๊ฐ€ ํ™œ์„ฑํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
257
- else:
258
- print("โ„น๏ธ OAuth๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค. (์ˆ˜๋™ ํ† ํฐ ์ž…๋ ฅ ๋ชจ๋“œ)")
259
-
260
- print("="*50 + "\n")
261
-
262
- demo.launch(
263
- ssr_mode=False, # SSR ๋น„ํ™œ์„ฑํ™”๋กœ ๊ฒฝ๊ณ  ์ œ๊ฑฐ
264
- show_error=True,
265
- quiet=True # Gradio ๊ธฐ๋ณธ ์ถœ๋ ฅ ์ตœ์†Œํ™”
266
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ HF Space Auto-Deployer
4
+ ----------------------
5
+ ๊ณต๊ฐœ Git ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ Hugging Face Gradio Space๋กœ ์ž๋™ ๋ณ€ํ™˜ ๋ฐ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค.
6
+
7
+ ํ•„์š” ํ™˜๊ฒฝ๋ณ€์ˆ˜:
8
+ - BAPI_TOKEN: Brave Search API Key
9
+ - FRIENDLI_TOKEN: Friendli AI API Token
10
+ - HF_TOKEN (์„ ํƒ): ๊ธฐ๋ณธ HuggingFace ํ† ํฐ
11
+ """
12
+
13
  import os
14
  import sys
15
+ import json
16
+ import argparse
17
+ import subprocess
18
+ import tempfile
19
+ import textwrap
20
+ import requests
21
+ import shutil
22
  from pathlib import Path
23
+ from typing import Optional, Dict, List
24
 
25
+ import gradio as gr
26
+ import git
27
+ from huggingface_hub import HfApi, login
28
 
29
+ # ========== Brave Search ํ—ฌํผ ========== #
30
+ def brave_search_repo(repo_url: str, count: int = 5) -> List[Dict]:
31
+ """Brave Search API๋กœ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ˆ˜์ง‘"""
32
+ api_key = os.getenv("BAPI_TOKEN")
33
+ if not api_key:
34
+ raise RuntimeError("ํ™˜๊ฒฝ๋ณ€์ˆ˜ BAPI_TOKEN์ด ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
35
+
36
+ headers = {"X-Subscription-Token": api_key, "Accept": "application/json"}
37
+ params = {"q": f'site:github.com "{repo_url}"', "count": count, "search_lang": "en"}
38
+
39
+ try:
40
+ resp = requests.get(
41
+ "https://api.search.brave.com/res/v1/web/search",
42
+ headers=headers,
43
+ params=params,
44
+ timeout=10
45
+ )
46
+ resp.raise_for_status()
47
+ return resp.json().get("web", {}).get("results", [])
48
+ except Exception as e:
49
+ print(f"โš ๏ธ Brave Search ๊ฒฝ๊ณ : {e}")
50
+ return []
51
 
52
+ # ========== Friendli LLM ํ—ฌํผ ========== #
53
+ def friendli_generate_scaffold(context: str) -> Dict:
54
+ """Friendli AI๋กœ app.py ๋ฐ requirements.txt ์ž๋™ ์ƒ์„ฑ"""
55
+ token = os.getenv("FRIENDLI_TOKEN")
56
+ if not token:
57
+ raise RuntimeError("ํ™˜๊ฒฝ๋ณ€์ˆ˜ FRIENDLI_TOKEN์ด ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
58
+
59
+ payload = {
60
+ "model": "meta-llama-3.1-70b-instruct",
61
+ "messages": [
62
+ {
63
+ "role": "system",
64
+ "content": textwrap.dedent("""
65
+ You are an expert Hugging Face Space architect. Given repository context,
66
+ generate a Gradio app that showcases the repository's functionality.
67
+
68
+ Output a JSON with these keys:
69
+ - app_py: Complete Gradio app code
70
+ - requirements_txt: Required Python packages
71
+ - need_docker: Boolean for Docker requirement
72
+ - dockerfile: Dockerfile content (if need_docker is true)
73
+ - summary: Brief description of the generated app
74
+
75
+ Important guidelines:
76
+ 1. Always use Gradio for the interface
77
+ 2. Make the app functional and user-friendly
78
+ 3. Include proper error handling
79
+ 4. Add clear instructions in the interface
80
+ 5. Use appropriate Gradio components for the task
81
+ """)
82
+ },
83
+ {"role": "user", "content": context}
84
+ ],
85
+ "max_tokens": 16384,
86
+ "temperature": 0.7,
87
+ "top_p": 0.9,
88
+ "stream": False
89
+ }
90
+
91
+ headers = {
92
+ "Authorization": f"Bearer {token}",
93
+ "Content-Type": "application/json"
94
+ }
95
+
96
+ try:
97
+ r = requests.post(
98
+ "https://api.friendli.ai/serverless/v1/chat/completions",
99
+ json=payload,
100
+ headers=headers,
101
+ timeout=120
102
+ )
103
+ r.raise_for_status()
104
+
105
+ # JSON ์‘๋‹ต ํŒŒ์‹ฑ
106
+ response_text = r.json()["choices"][0]["message"]["content"]
107
 
108
+ # JSON ๋ธ”๋ก ์ถ”์ถœ (```json ... ``` ํ˜•์‹ ์ฒ˜๋ฆฌ)
109
+ if "```json" in response_text:
110
+ start = response_text.find("```json") + 7
111
+ end = response_text.find("```", start)
112
+ response_text = response_text[start:end].strip()
113
+
114
+ return json.loads(response_text)
115
+ except json.JSONDecodeError as e:
116
+ print(f"โš ๏ธ JSON ํŒŒ์‹ฑ ์˜ค๋ฅ˜: {e}")
117
+ # ๊ธฐ๋ณธ Gradio ์•ฑ ๋ฐ˜ํ™˜
118
+ return {
119
+ "app_py": textwrap.dedent("""
120
+ import gradio as gr
121
+
122
+ def main():
123
+ return "This is an auto-generated Gradio app. Please customize it based on your repository."
124
+
125
+ demo = gr.Interface(
126
+ fn=main,
127
+ inputs=None,
128
+ outputs="text",
129
+ title="Auto-Generated Space",
130
+ description="This Space was automatically created. Please update app.py to add your functionality."
131
+ )
132
+
133
+ if __name__ == "__main__":
134
+ demo.launch()
135
+ """),
136
+ "requirements_txt": "gradio>=4.0.0",
137
+ "need_docker": False,
138
+ "summary": "Basic Gradio template - please customize based on your repository"
139
+ }
140
+
141
+ # ========== ๋ฉ”์ธ ๋ฐฐํฌ ๋กœ์ง ========== #
142
+ def deploy(repo_url: str, hf_token: str, private: bool = False, hardware: Optional[str] = None) -> str:
143
+ """๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ Gradio Space๋กœ ๋ฐฐํฌํ•˜๊ณ  Space URL ๋ฐ˜ํ™˜"""
144
+ # HF ๋กœ๊ทธ์ธ
145
+ login(hf_token)
146
+ api = HfApi(token=hf_token)
147
+
148
+ # ์‚ฌ์šฉ์ž ์ •๋ณด ๋ฐ Space ์ด๋ฆ„ ์ƒ์„ฑ
149
+ user = api.whoami()["name"]
150
+ repo_name = Path(repo_url.rstrip("/")).name.lower()
151
+ repo_name = repo_name.replace(".", "-").replace("_", "-")
152
+ space_id = f"{user}/{repo_name}-space"
153
+
154
+ print(f"๐Ÿ“ฆ Space ID: {space_id}")
155
 
156
+ # Space ์ƒ์„ฑ
157
+ api.create_repo(
158
+ repo_id=space_id,
159
+ repo_type="space",
160
+ space_sdk="gradio",
161
+ private=private,
162
+ exist_ok=True
163
+ )
164
 
165
+ # Hardware ์„ค์ • (ํ•„์š”ํ•œ ๊ฒฝ์šฐ)
166
+ if hardware:
167
+ try:
168
+ api.request_space_hardware(repo_id=space_id, hardware=hardware)
169
+ print(f"๐Ÿ–ฅ๏ธ Hardware ์„ค์ •: {hardware}")
170
+ except Exception as e:
171
+ print(f"โš ๏ธ Hardware ์„ค์ • ์‹คํŒจ: {e}")
172
 
173
+ with tempfile.TemporaryDirectory() as work_dir:
174
+ # 1) Brave Search๋กœ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ˆ˜์ง‘
175
+ print("๐Ÿ” ๋ ˆํฌ์ง€ํ† ๋ฆฌ ์ •๋ณด ์ˆ˜์ง‘ ์ค‘...")
176
+ brave_meta = brave_search_repo(repo_url)
177
+
178
+ # 2) ์›๋ณธ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ํด๋ก 
179
+ print("๐Ÿ“ฅ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ํด๋ก  ์ค‘...")
180
+ src_path = Path(work_dir) / "source"
181
+ git.Repo.clone_from(repo_url, src_path, depth=1)
182
+
183
+ # README ์ฝ๊ธฐ
184
+ readme_content = ""
185
+ readme_path = src_path / "README.md"
186
+ if readme_path.exists():
187
+ readme_content = readme_path.read_text(encoding="utf-8", errors="ignore")[:4000]
188
+
189
+ # ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ํŒŒ์•…
190
+ tree_output = subprocess.run(
191
+ ["bash", "-c", f"find {src_path} -type f -name '*.py' -o -name '*.md' -o -name '*.txt' -o -name '*.json' -o -name '*.yaml' -o -name '*.yml' | head -n 50"],
192
+ capture_output=True,
193
+ text=True
194
+ ).stdout
195
+
196
+ # ์ปจํ…์ŠคํŠธ ์ƒ์„ฑ
197
+ context = textwrap.dedent(f"""
198
+ ## Repository URL
199
+ {repo_url}
200
+
201
+ ## Brave Search Metadata
202
+ {json.dumps(brave_meta, ensure_ascii=False, indent=2)}
203
+
204
+ ## Repository Structure
205
+ {tree_output}
206
+
207
+ ## README.md Content (first 4KB)
208
+ {readme_content}
209
+
210
+ Please create a Gradio app that best showcases this repository's functionality.
211
+ If it's a model, create an inference interface. If it's a dataset, create a viewer.
212
+ If it's a library, create a demo. Make it user-friendly and functional.
213
+ """)
214
+
215
+ # 3) Friendli AI๋กœ ์Šค์บํด๋“œ ์ƒ์„ฑ
216
+ print("๐Ÿค– AI๋กœ Gradio ์•ฑ ์ƒ์„ฑ ์ค‘...")
217
+ scaffold = friendli_generate_scaffold(context)
218
+
219
+ # 4) Space ๋ ˆํฌ์ง€ํ† ๋ฆฌ ํด๋ก  ๋ฐ ํŒŒ์ผ ์ž‘์„ฑ
220
+ print("๐Ÿ“ค Space์— ํŒŒ์ผ ์—…๋กœ๋“œ ์ค‘...")
221
+ dst_path = Path(work_dir) / "space"
222
+
223
+ # HTTPS URL with token for authentication
224
+ space_url = f"https://{hf_token}@huggingface.co/spaces/{space_id}"
225
+ space_repo = git.Repo.clone_from(space_url, dst_path, depth=1)
226
+
227
+ # ํŒŒ์ผ ์ž‘์„ฑ
228
+ (dst_path / "app.py").write_text(scaffold["app_py"], encoding="utf-8")
229
+ (dst_path / "requirements.txt").write_text(scaffold["requirements_txt"], encoding="utf-8")
230
+
231
+ if scaffold.get("need_docker"):
232
+ (dst_path / "Dockerfile").write_text(scaffold["dockerfile"], encoding="utf-8")
233
+
234
+ # README.md ์ƒ์„ฑ
235
+ readme_content = f"""---
236
+ title: {repo_name.replace("-", " ").title()}
237
+ emoji: ๐Ÿš€
238
+ colorFrom: blue
239
+ colorTo: purple
240
+ sdk: gradio
241
+ sdk_version: 4.44.1
242
+ app_file: app.py
243
+ pinned: false
244
+ ---
245
 
246
+ # {repo_name.replace("-", " ").title()}
247
+
248
+ Automatically deployed from: {repo_url}
249
+
250
+ ## Summary
251
+ {scaffold.get("summary", "Auto-generated Gradio Space")}
252
+
253
+ ---
254
+ *Created by HF Space Auto-Deployer*
255
+ """
256
+ (dst_path / "README.md").write_text(readme_content, encoding="utf-8")
257
+
258
+ # Git ์ปค๋ฐ‹ ๋ฐ ํ‘ธ์‹œ
259
+ space_repo.index.add(["app.py", "requirements.txt", "README.md"])
260
+ if scaffold.get("need_docker"):
261
+ space_repo.index.add(["Dockerfile"])
262
 
263
+ # Git ์„ค์ •
264
+ space_repo.config_writer().set_value("user", "name", user).release()
265
+ space_repo.config_writer().set_value("user", "email", f"{user}@users.noreply.huggingface.co").release()
266
+
267
+ space_repo.index.commit("Initial auto-deployment")
268
+
269
+ # ํ‘ธ์‹œ
270
+ origin = space_repo.remote("origin")
271
+ origin.push()
272
+
273
+ return f"https://huggingface.co/spaces/{space_id}"
274
+
275
+ # ========== Gradio UI ========== #
276
+ def launch_deploy(repo_url: str, private: bool, request: gr.Request) -> str:
277
+ """Gradio UI์—์„œ ํ˜ธ์ถœ๋˜๋Š” ๋ฐฐํฌ ํ•จ์ˆ˜"""
278
+ # ํ† ํฐ ๊ฐ€์ ธ์˜ค๊ธฐ (์šฐ์„ ์ˆœ์œ„: Gradio ์ธ์ฆ โ†’ ํ™˜๊ฒฝ๋ณ€์ˆ˜)
279
+ hf_token = None
280
 
281
+ # Gradio ์ธ์ฆ ํ—ค๋” ํ™•์ธ
282
+ auth_header = request.headers.get("authorization")
283
+ if auth_header and auth_header.startswith("Bearer "):
284
+ hf_token = auth_header.split(" ")[1].strip()
285
 
286
+ # ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํด๋ฐฑ
287
+ if not hf_token:
288
+ hf_token = os.environ.get("HF_TOKEN")
289
+
290
+ if not hf_token:
291
+ return """### โŒ ์ธ์ฆ ํ•„์š”
292
 
293
+ ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ์ธ์ฆํ•ด์ฃผ์„ธ์š”:
294
+ 1. **์šฐ์ธก ์ƒ๋‹จ ํ”„๋กœํ•„ โ†’ Sign in with Hugging Face**
295
+ 2. **Space Settings โ†’ Variables and secrets โ†’ HF_TOKEN ์„ค์ •**"""
296
 
297
+ # URL ๊ฒ€์ฆ
 
 
 
 
298
  repo_url = repo_url.strip()
299
+ if not repo_url:
300
+ return "### โŒ Repository URL์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
301
 
302
+ if not any(repo_url.startswith(prefix) for prefix in ["https://github.com/", "http://github.com/"]):
303
+ return """### โŒ ์ž˜๋ชป๋œ URL ํ˜•์‹
 
304
 
305
+ GitHub URL์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.
306
+ ์˜ˆ: https://github.com/username/repository"""
307
 
308
+ # ๋ฐฐํฌ ์‹คํ–‰
309
  try:
310
+ space_url = deploy(repo_url, hf_token, private)
311
+ return f"""### โœ… Space ๋ฐฐํฌ ์™„๋ฃŒ!
312
 
313
  ๐ŸŽ‰ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฐฐํฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!
314
 
315
+ **Space URL**: [{space_url}]({space_url})
316
+
317
+ **๋‹ค์Œ ๋‹จ๊ณ„:**
318
+ 1. Space ํŽ˜์ด์ง€ ๋ฐฉ๋ฌธ
319
+ 2. ๋นŒ๋“œ ๋กœ๊ทธ ํ™•์ธ (์šฐ์ธก ์ƒ๋‹จ "Logs" ํƒญ)
320
+ 3. ๋นŒ๋“œ ์™„๋ฃŒ ๋Œ€๊ธฐ (๋ณดํ†ต 2-5๋ถ„)
321
+ 4. ํ•„์š”์‹œ app.py ์ˆ˜์ •
322
 
323
  ---
324
+ ๐Ÿ’ก **ํŒ**: Space๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋ฉด Files ํƒญ์—์„œ app.py๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."""
325
+
326
  except Exception as e:
327
  error_msg = str(e)
328
 
329
+ # ์ƒ์„ธํ•œ ์˜ค๋ฅ˜ ์•ˆ๋‚ด
330
  if "BAPI_TOKEN" in error_msg:
331
  return """### โŒ Brave Search API ํ† ํฐ ํ•„์š”
332
 
333
+ **์„ค์ • ๋ฐฉ๋ฒ•:**
334
+ 1. [Brave Search API](https://brave.com/search/api/) ๊ฐ€์ž…
335
+ 2. ๋ฌด๋ฃŒ API Key ๋ฐœ๊ธ‰
336
+ 3. **์ด Space์˜** Settings โ†’ Variables and secrets
337
+ 4. `BAPI_TOKEN` = `[๋ฐœ๊ธ‰๋ฐ›์€ ํ‚ค]` ์ถ”๊ฐ€"""
338
+
339
  elif "FRIENDLI_TOKEN" in error_msg:
340
  return """### โŒ Friendli AI ํ† ํฐ ํ•„์š”
341
 
342
+ **์„ค์ • ๋ฐฉ๋ฒ•:**
343
+ 1. [Friendli AI](https://friendli.ai/) ๊ฐ€์ž…
344
+ 2. API Key ๋ฐœ๊ธ‰
345
+ 3. **์ด Space์˜** Settings โ†’ Variables and secrets
346
+ 4. `FRIENDLI_TOKEN` = `[๋ฐœ๊ธ‰๋ฐ›์€ ํ‚ค]` ์ถ”๊ฐ€"""
347
+
348
+ elif "401" in error_msg or "403" in error_msg or "Unauthorized" in error_msg:
 
349
  return """### โŒ ์ธ์ฆ ์‹คํŒจ
350
 
351
+ **ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•:**
352
+ 1. [ํ† ํฐ ํŽ˜์ด์ง€](https://huggingface.co/settings/tokens) ๋ฐฉ๋ฌธ
353
+ 2. "New token" ํด๋ฆญ
354
+ 3. **Write** ๊ถŒํ•œ ์ฒดํฌ โœ…
355
+ 4. Space Settings์—์„œ HF_TOKEN ์—…๋ฐ์ดํŠธ"""
356
+
357
  else:
358
  return f"""### โŒ ๋ฐฐํฌ ์˜ค๋ฅ˜
359
 
360
+ **์˜ค๋ฅ˜ ๋‚ด์šฉ:**
361
+ ```
362
+ {error_msg}
363
+ ```
364
 
365
+ **์ผ๋ฐ˜์ ์ธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•:**
366
+ 1. Repository๊ฐ€ public์ธ์ง€ ํ™•์ธ
367
+ 2. URL ํ˜•์‹ ํ™•์ธ (https://github.com/user/repo)
368
+ 3. ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ํ™•์ธ
369
+ 4. ์ž ์‹œ ํ›„ ์žฌ์‹œ๋„"""
370
 
371
+ # ========== Gradio App ========== #
372
+ def create_ui():
373
+ """Gradio UI ์ƒ์„ฑ"""
374
+ with gr.Blocks(
375
+ title="HF Space Auto-Deployer",
376
+ theme=gr.themes.Soft(),
377
+ css="""
378
+ .main-container {
379
+ max-width: 800px;
380
+ margin: 0 auto;
381
+ padding: 20px;
382
+ }
383
+ .header {
384
+ text-align: center;
385
+ margin-bottom: 30px;
386
+ padding: 20px;
387
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
388
+ color: white;
389
+ border-radius: 10px;
390
+ }
391
+ .header h1 {
392
+ margin: 0;
393
+ font-size: 2.5em;
394
+ }
395
+ .header p {
396
+ margin: 10px 0 0 0;
397
+ opacity: 0.9;
398
+ }
399
+ .gr-button-primary {
400
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
401
+ border: none !important;
402
+ font-size: 1.1em !important;
403
+ padding: 12px 30px !important;
404
+ }
405
+ .gr-button-primary:hover {
406
+ transform: translateY(-2px);
407
+ box-shadow: 0 5px 15px rgba(0,0,0,0.2);
408
+ }
409
+ .status-box {
410
+ padding: 20px;
411
+ border-radius: 10px;
412
+ margin-top: 20px;
413
+ border: 1px solid #e0e0e0;
414
+ background-color: #f9f9f9;
415
+ }
416
+ .info-box {
417
+ background-color: #e3f2fd;
418
+ padding: 15px;
419
+ border-radius: 8px;
420
+ border-left: 4px solid #2196F3;
421
+ margin: 10px 0;
422
+ }
423
+ .examples-box {
424
+ background-color: #f3e5f5;
425
+ padding: 15px;
426
+ border-radius: 8px;
427
+ margin: 10px 0;
428
+ }
429
+ """
430
+ ) as demo:
431
+ with gr.Column(elem_classes="main-container"):
432
+ # ํ—ค๋”
433
+ gr.HTML("""
434
+ <div class="header">
435
+ <h1>๐Ÿš€ GitHub โ†’ HuggingFace Space</h1>
436
+ <p>AI๊ฐ€ ๋‹น์‹ ์˜ GitHub ํ”„๋กœ์ ํŠธ๋ฅผ Gradio ์•ฑ์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค</p>
437
+ </div>
438
+ """)
439
 
440
+ # ์ธ์ฆ ์•ˆ๋‚ด
 
 
 
 
 
 
 
 
 
 
441
  gr.Markdown("""
442
+ <div class="info-box">
443
+ <b>๐Ÿ” ์ธ์ฆ ๋ฐฉ๋ฒ•:</b><br>
444
+ โ€ข <b>๋ฐฉ๋ฒ• 1</b>: ์šฐ์ธก ์ƒ๋‹จ ํ”„๋กœํ•„ โ†’ Sign in with Hugging Face<br>
445
+ โ€ข <b>๋ฐฉ๋ฒ• 2</b>: Space Settings์—์„œ HF_TOKEN ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •
446
+ </div>
447
  """)
448
 
449
+ # ์ž…๋ ฅ ํ•„๋“œ
450
+ with gr.Group():
451
+ repo_input = gr.Textbox(
452
+ label="๐Ÿ“ฆ GitHub Repository URL",
453
+ placeholder="https://github.com/username/repository",
454
+ info="Public repository URL์„ ์ž…๋ ฅํ•˜์„ธ์š”",
455
+ lines=1
456
+ )
457
+
458
+ private_checkbox = gr.Checkbox(
459
+ label="๐Ÿ”’ Private Space๋กœ ์ƒ์„ฑ",
460
+ value=False,
461
+ info="์ฒดํฌํ•˜๋ฉด ๋ณธ์ธ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ Space๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค"
462
+ )
 
 
 
 
 
 
463
 
464
+ # ๋ฐฐํฌ ๋ฒ„ํŠผ
465
  deploy_btn = gr.Button(
466
+ "๐Ÿš€ Space ์ƒ์„ฑํ•˜๊ธฐ",
467
  variant="primary",
468
  size="lg"
469
  )
470
 
471
+ # ์ƒํƒœ ์ถœ๋ ฅ
472
  output_status = gr.Markdown(
473
  elem_classes="status-box",
474
  visible=False
475
  )
476
 
477
+ # ์˜ˆ์‹œ
478
+ gr.HTML("""
479
+ <div class="examples-box">
480
+ <b>๐Ÿ’ก ์˜ˆ์‹œ ํ”„๋กœ์ ํŠธ:</b><br>
481
+ โ€ข <code>https://github.com/gradio-app/gradio/tree/main/demo/hello_world</code><br>
482
+ โ€ข <code>https://github.com/huggingface/transformers</code><br>
483
+ โ€ข <code>https://github.com/CompVis/stable-diffusion</code>
484
+ </div>
485
+ """)
486
+
487
+ # ์‚ฌ์šฉ ๊ฐ€์ด๋“œ
488
+ with gr.Accordion("๐Ÿ“š ์‚ฌ์šฉ ๊ฐ€์ด๋“œ", open=False):
489
+ gr.Markdown("""
490
+ ### ์ž‘๋™ ์›๋ฆฌ
491
+ 1. **๐Ÿ” ๋ถ„์„**: Brave Search๋กœ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ์ •๋ณด ์ˆ˜์ง‘
492
+ 2. **๐Ÿค– ์ƒ์„ฑ**: Friendli AI๊ฐ€ ๋งž์ถคํ˜• Gradio ์•ฑ ์ฝ”๋“œ ์ƒ์„ฑ
493
+ 3. **๐Ÿ“ค ๋ฐฐํฌ**: HuggingFace Space์— ์ž๋™ ์—…๋กœ๋“œ ๋ฐ ๋นŒ๋“œ
494
+
495
+ ### ์ง€์›ํ•˜๋Š” ํ”„๋กœ์ ํŠธ ์œ ํ˜•
496
+ - โœ… **ML ๋ชจ๋ธ**: ์ถ”๋ก  ์ธํ„ฐํŽ˜์ด์Šค ์ž๋™ ์ƒ์„ฑ
497
+ - โœ… **๋ฐ์ดํ„ฐ์…‹**: ๋ฐ์ดํ„ฐ ํƒ์ƒ‰๊ธฐ ์ƒ์„ฑ
498
+ - โœ… **๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ**: ๋ฐ๋ชจ ์•ฑ ์ƒ์„ฑ
499
+ - โœ… **์ผ๋ฐ˜ ํ”„๋กœ์ ํŠธ**: ๊ธฐ๋Šฅ ์‡ผ์ผ€์ด์Šค ์ƒ์„ฑ
500
+
501
+ ### ํ•„์š”ํ•œ API ํ‚ค
502
+ 1. **BAPI_TOKEN**: [Brave Search API](https://brave.com/search/api/) (๋ฌด๋ฃŒ)
503
+ 2. **FRIENDLI_TOKEN**: [Friendli AI](https://friendli.ai/) (๋ฌด๋ฃŒ ํฌ๋ ˆ๋”ง ์ œ๊ณต)
504
+
505
+ ### ๋ฌธ์ œ ํ•ด๊ฒฐ
506
+ - **๋นŒ๋“œ ์‹คํŒจ**: Space์˜ Logs ํƒญ ํ™•์ธ
507
+ - **์•ฑ ์ˆ˜์ •**: Files ํƒญ์—์„œ app.py ์ง์ ‘ ํŽธ์ง‘
508
+ - **GPU ํ•„์š”**: Space Settings์—์„œ Hardware ๋ณ€๊ฒฝ
509
+ """)
510
 
511
+ # ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
512
+ deploy_btn.click(
513
+ fn=launch_deploy,
514
+ inputs=[repo_input, private_checkbox],
515
+ outputs=output_status
516
+ ).then(
517
+ fn=lambda: gr.update(visible=True),
518
+ outputs=output_status
519
+ )
520
+
521
+ return demo
522
 
523
+ # ========== CLI ์ง€์› ========== #
524
+ def main():
525
+ """CLI ์‹คํ–‰์„ ์œ„ํ•œ ๋ฉ”์ธ ํ•จ์ˆ˜"""
526
+ parser = argparse.ArgumentParser(description="Git ๋ ˆํฌ๋ฅผ Hugging Face Space๋กœ ์ž๋™ ๋ฐฐํฌ")
527
+ parser.add_argument("--repo_url", help="GitHub repository URL")
528
+ parser.add_argument("--hf_token", help="HuggingFace write token")
529
+ parser.add_argument("--private", action="store_true", help="Create private Space")
530
+ parser.add_argument("--hardware", help="GPU tier (e.g., 't4-medium')")
531
+ parser.add_argument("--no-ui", action="store_true", help="Run without Gradio UI")
532
 
533
+ args = parser.parse_args()
 
 
 
 
 
534
 
535
+ # CLI ๋ชจ๋“œ
536
+ if args.no_ui and args.repo_url and args.hf_token:
537
+ try:
538
+ url = deploy(args.repo_url, args.hf_token, args.private, args.hardware)
539
+ print(f"โœ… ๋ฐฐํฌ ์„ฑ๊ณต: {url}")
540
+ except Exception as e:
541
+ print(f"โŒ ๋ฐฐํฌ ์‹คํŒจ: {e}", file=sys.stderr)
542
+ sys.exit(1)
543
+ # Gradio UI ๋ชจ๋“œ
544
  else:
545
+ # ํ™˜๊ฒฝ ์ƒํƒœ ์ถœ๋ ฅ
546
+ print("\n" + "="*60)
547
+ print("๐Ÿš€ HF Space Auto-Deployer")
548
+ print("="*60)
549
+
550
+ # ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ฒดํฌ
551
+ env_checks = []
552
+ env_checks.append("โœ… HF_TOKEN" if os.getenv("HF_TOKEN") else "โš ๏ธ HF_TOKEN (์„ ํƒ์‚ฌํ•ญ)")
553
+ env_checks.append("โœ… BAPI_TOKEN" if os.getenv("BAPI_TOKEN") else "โŒ BAPI_TOKEN (ํ•„์ˆ˜)")
554
+ env_checks.append("โœ… FRIENDLI_TOKEN" if os.getenv("FRIENDLI_TOKEN") else "โŒ FRIENDLI_TOKEN (ํ•„์ˆ˜)")
555
+
556
+ print("ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ƒํƒœ:")
557
+ for check in env_checks:
558
+ print(f" {check}")
559
+
560
+ print("="*60 + "\n")
561
+
562
+ # Gradio ์•ฑ ์‹คํ–‰
563
+ demo = create_ui()
564
+ demo.launch(
565
+ share=False,
566
+ server_name="0.0.0.0",
567
+ server_port=7860
568
+ )
569
+
570
+ if __name__ == "__main__":
571
+ main()