openfree commited on
Commit
611d889
โ€ข
1 Parent(s): 1c92bee

Create app-backup.py

Browse files
Files changed (1) hide show
  1. app-backup.py +375 -0
app-backup.py ADDED
@@ -0,0 +1,375 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import gradio as gr
3
+ from datetime import datetime
4
+ import random
5
+
6
+ USERNAME = "openfree"
7
+
8
+ def format_timestamp(timestamp):
9
+ if not timestamp:
10
+ return 'N/A'
11
+ try:
12
+ # ๋ฌธ์ž์—ด์ธ ๊ฒฝ์šฐ
13
+ if isinstance(timestamp, str):
14
+ dt = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
15
+ # ์ •์ˆ˜(๋ฐ€๋ฆฌ์ดˆ)์ธ ๊ฒฝ์šฐ
16
+ elif isinstance(timestamp, (int, float)):
17
+ dt = datetime.fromtimestamp(timestamp / 1000) # ๋ฐ€๋ฆฌ์ดˆ๋ฅผ ์ดˆ๋กœ ๋ณ€ํ™˜
18
+ else:
19
+ return 'N/A'
20
+ return dt.strftime('%Y-%m-%d %H:%M')
21
+ except Exception as e:
22
+ print(f"Timestamp conversion error: {str(e)} for timestamp: {timestamp}")
23
+ return 'N/A'
24
+
25
+
26
+ def should_exclude_space(space_name):
27
+ """ํŠน์ • ์ŠคํŽ˜์ด์Šค๋ฅผ ์ œ์™ธํ•˜๋Š” ํ•„ํ„ฐ ํ•จ์ˆ˜"""
28
+ exclude_keywords = [
29
+ 'mixgen3', 'ginid', 'mouse', 'flxtrainlora',
30
+ 'vidslicegpu', 'stickimg', 'ultpixgen', 'SORA',
31
+ 'badassgi', 'newsplus', 'chargen', 'news',
32
+ 'testhtml'
33
+ ]
34
+
35
+ return any(keyword.lower() in space_name.lower() for keyword in exclude_keywords)
36
+
37
+ def get_pastel_color(index):
38
+ """Generate unique pastel colors based on index"""
39
+ pastel_colors = [
40
+ '#FFE6E6', # ์—ฐํ•œ ๋ถ„ํ™
41
+ '#FFE6FF', # ์—ฐํ•œ ๋ณด๋ผ
42
+ '#E6E6FF', # ์—ฐํ•œ ํŒŒ๋ž‘
43
+ '#E6FFFF', # ์—ฐํ•œ ํ•˜๋Š˜
44
+ '#E6FFE6', # ์—ฐํ•œ ์ดˆ๋ก
45
+ '#FFFFE6', # ์—ฐํ•œ ๋…ธ๋ž‘
46
+ '#FFF0E6', # ์—ฐํ•œ ์ฃผํ™ฉ
47
+ '#F0E6FF', # ์—ฐํ•œ ๋ผ๋ฒค๋”
48
+ '#FFE6F0', # ์—ฐํ•œ ๋กœ์ฆˆ
49
+ '#E6FFF0', # ์—ฐํ•œ ๋ฏผํŠธ
50
+ '#F0FFE6', # ์—ฐํ•œ ๋ผ์ž„
51
+ '#FFE6EB', # ์—ฐํ•œ ์ฝ”๋ž„
52
+ '#E6EBFF', # ์—ฐํ•œ ํผํ”Œ๋ธ”๋ฃจ
53
+ '#FFE6F5', # ์—ฐํ•œ ํ•‘ํฌ
54
+ '#E6FFF5', # ์—ฐํ•œ ํ„ฐ์ฝ”์ด์ฆˆ
55
+ '#F5E6FF', # ์—ฐํ•œ ๋ชจ๋ธŒ
56
+ '#FFE6EC', # ์—ฐํ•œ ์‚ด๋ชฌ
57
+ '#E6FFEC', # ์—ฐํ•œ ์Šคํ”„๋ง๊ทธ๋ฆฐ
58
+ '#ECE6FF', # ์—ฐํ•œ ํŽ˜๋ฆฌ์œ™ํด
59
+ '#FFE6F7', # ์—ฐํ•œ ๋งค๊ทธ๋†€๋ฆฌ์•„
60
+ ]
61
+ return pastel_colors[index % len(pastel_colors)]
62
+
63
+ def get_space_card(space, index):
64
+ """Generate HTML card for a space with colorful design and lots of emojis"""
65
+ space_id = space.get('id', '')
66
+ space_name = space_id.split('/')[-1]
67
+ likes = space.get('likes', 0)
68
+ created_at = format_timestamp(space.get('createdAt'))
69
+ sdk = space.get('sdk', 'N/A')
70
+
71
+ # SDK๋ณ„ ์ด๋ชจ์ง€ ๋ฐ ๊ด€๋ จ ์ด๋ชจ์ง€ ์„ธํŠธ
72
+ sdk_emoji_sets = {
73
+ 'gradio': {
74
+ 'main': '๐ŸŽจ',
75
+ 'related': ['๐Ÿ–ผ๏ธ', '๐ŸŽญ', '๐ŸŽช', '๐ŸŽ ', '๐ŸŽก', '๐ŸŽข', '๐ŸŽฏ', '๐ŸŽฒ', '๐ŸŽฐ', '๐ŸŽณ']
76
+ },
77
+ 'streamlit': {
78
+ 'main': 'โšก',
79
+ 'related': ['๐Ÿ’ซ', 'โœจ', 'โญ', '๐ŸŒŸ', '๐Ÿ’ฅ', 'โšก', '๐Ÿ”ฅ', '๐ŸŒˆ', '๐ŸŽ†', '๐ŸŽ‡']
80
+ },
81
+ 'docker': {
82
+ 'main': '๐Ÿณ',
83
+ 'related': ['๐Ÿ‹', '๐ŸŒŠ', '๐ŸŒ', '๐Ÿšข', 'โ›ด๏ธ', '๐Ÿ›ฅ๏ธ', '๐Ÿ ', '๐Ÿก', '๐Ÿฆˆ', '๐Ÿฌ']
84
+ },
85
+ 'static': {
86
+ 'main': '๐Ÿ“„',
87
+ 'related': ['๐Ÿ“', '๐Ÿ“ฐ', '๐Ÿ“‘', '๐Ÿ—‚๏ธ', '๐Ÿ“', '๐Ÿ“‚', '๐Ÿ“š', '๐Ÿ“–', '๐Ÿ“’', '๐Ÿ“”']
88
+ },
89
+ 'panel': {
90
+ 'main': '๐Ÿ“Š',
91
+ 'related': ['๐Ÿ“ˆ', '๐Ÿ“‰', '๐Ÿ’น', '๐Ÿ“‹', '๐Ÿ“Œ', '๐Ÿ“', '๐Ÿ—บ๏ธ', '๐ŸŽฏ', '๐Ÿ“', '๐Ÿ“']
92
+ },
93
+ 'N/A': {
94
+ 'main': '๐Ÿ”ง',
95
+ 'related': ['๐Ÿ”จ', 'โš’๏ธ', '๐Ÿ› ๏ธ', 'โš™๏ธ', '๐Ÿ”ฉ', 'โ›๏ธ', 'โšก', '๐Ÿ”Œ', '๐Ÿ’ก', '๐Ÿ”‹']
96
+ }
97
+ }
98
+
99
+ # SDK์— ๋”ฐ๋ฅธ ์ด๋ชจ์ง€ ์„ ํƒ
100
+ sdk_lower = sdk.lower()
101
+ bg_color = get_pastel_color(index) # ์ธ๋ฑ์Šค ๊ธฐ๋ฐ˜ ์ƒ‰์ƒ ์„ ํƒ
102
+ emoji_set = sdk_emoji_sets.get(sdk_lower, sdk_emoji_sets['N/A'])
103
+ main_emoji = emoji_set['main']
104
+
105
+ # ๋žœ๋คํ•˜๊ฒŒ 3๊ฐœ์˜ ๊ด€๋ จ ์ด๋ชจ์ง€ ์„ ํƒ
106
+ decorative_emojis = random.sample(emoji_set['related'], 3)
107
+
108
+ # ์ถ”๊ฐ€ ์žฅ์‹์šฉ ์ด๋ชจ์ง€
109
+ general_emojis = ['๐Ÿš€', '๐Ÿ’ซ', 'โญ', '๐ŸŒŸ', 'โœจ', '๐Ÿ’ฅ', '๐Ÿ”ฅ', '๐ŸŒˆ', '๐ŸŽฏ', '๐ŸŽจ',
110
+ '๐ŸŽญ', '๐ŸŽช', '๐ŸŽข', '๐ŸŽก', '๐ŸŽ ', '๐ŸŽช', '๐ŸŽญ', '๐ŸŽจ', '๐ŸŽฏ', '๐ŸŽฒ']
111
+ random_emojis = random.sample(general_emojis, 3)
112
+
113
+ # ์ข‹์•„์š” ์ˆ˜์— ๋”ฐ๋ฅธ ํ•˜ํŠธ ์ด๋ชจ์ง€
114
+ heart_emoji = 'โค๏ธ' if likes > 100 else '๐Ÿ’–' if likes > 50 else '๐Ÿ’' if likes > 10 else '๐Ÿค'
115
+
116
+
117
+
118
+
119
+ return f"""
120
+ <div style='border: none;
121
+ padding: 25px;
122
+ margin: 15px;
123
+ border-radius: 20px;
124
+ background-color: {bg_color};
125
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
126
+ transition: all 0.3s ease-in-out;
127
+ position: relative;
128
+ overflow: hidden;'
129
+ onmouseover='this.style.transform="translateY(-5px) scale(1.02)"; this.style.boxShadow="0 8px 25px rgba(0,0,0,0.15)"'
130
+ onmouseout='this.style.transform="translateY(0) scale(1)"; this.style.boxShadow="0 4px 15px rgba(0,0,0,0.1)"'>
131
+ <div style='position: absolute; top: -15px; right: -15px; font-size: 100px; opacity: 0.1;'>
132
+ {main_emoji}
133
+ </div>
134
+ <div style='position: absolute; top: 10px; right: 10px; font-size: 20px;'>
135
+ {decorative_emojis[0]}
136
+ </div>
137
+ <div style='position: absolute; bottom: 10px; left: 10px; font-size: 20px;'>
138
+ {decorative_emojis[1]}
139
+ </div>
140
+ <div style='position: absolute; top: 50%; right: 10px; font-size: 20px;'>
141
+ {decorative_emojis[2]}
142
+ </div>
143
+ <h3 style='color: #2d2d2d;
144
+ margin: 0 0 20px 0;
145
+ font-size: 1.4em;
146
+ display: flex;
147
+ align-items: center;
148
+ gap: 10px;'>
149
+ <span style='font-size: 1.3em'>{random_emojis[0]}</span>
150
+ <a href='https://huggingface.co/spaces/{space_id}' target='_blank'
151
+ style='text-decoration: none; color: #2d2d2d;'>
152
+ {space_name}
153
+ </a>
154
+ <span style='font-size: 1.3em'>{random_emojis[1]}</span>
155
+ </h3>
156
+ <div style='margin: 15px 0; color: #444; background: rgba(255,255,255,0.5);
157
+ padding: 15px; border-radius: 12px;'>
158
+ <p style='margin: 8px 0;'>
159
+ <strong>SDK:</strong> {main_emoji} {sdk} {decorative_emojis[0]}
160
+ </p>
161
+ <p style='margin: 8px 0;'>
162
+ <strong>Created:</strong> ๐Ÿ“… {created_at} โฐ
163
+ </p>
164
+ <p style='margin: 8px 0;'>
165
+ <strong>Likes:</strong> {heart_emoji} {likes} {random_emojis[2]}
166
+ </p>
167
+ </div>
168
+ <div style='margin-top: 20px;
169
+ display: flex;
170
+ justify-content: space-between;
171
+ align-items: center;'>
172
+ <a href='https://huggingface.co/spaces/{space_id}' target='_blank'
173
+ style='background: linear-gradient(45deg, #0084ff, #00a3ff);
174
+ color: white;
175
+ padding: 10px 20px;
176
+ border-radius: 15px;
177
+ text-decoration: none;
178
+ display: inline-flex;
179
+ align-items: center;
180
+ gap: 8px;
181
+ font-weight: 500;
182
+ transition: all 0.3s;
183
+ box-shadow: 0 2px 8px rgba(0,132,255,0.3);'
184
+ onmouseover='this.style.transform="scale(1.05)"; this.style.boxShadow="0 4px 12px rgba(0,132,255,0.4)"'
185
+ onmouseout='this.style.transform="scale(1)"; this.style.boxShadow="0 2px 8px rgba(0,132,255,0.3)"'>
186
+ <span>View Space</span> ๐Ÿš€ {random_emojis[0]}
187
+ </a>
188
+ <span style='color: #666; font-size: 0.9em; opacity: 0.7;'>
189
+ ๐Ÿ†” {space_id} {decorative_emojis[2]}
190
+ </span>
191
+ </div>
192
+ </div>
193
+ """
194
+
195
+ def get_vercel_deployments():
196
+ """Vercel API๋ฅผ ํ†ตํ•ด ๋ฐฐํฌ๋œ ์„œ๋น„์Šค ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ"""
197
+ token = "A8IFZmgW2cqA4yUNlLPnci0N"
198
+ url = "https://api.vercel.com/v6/deployments"
199
+
200
+ headers = {
201
+ "Authorization": f"Bearer {token}",
202
+ "Content-Type": "application/json"
203
+ }
204
+
205
+ try:
206
+ response = requests.get(url, headers=headers)
207
+ if response.status_code != 200:
208
+ print(f"Vercel API Error: {response.text}")
209
+ return []
210
+
211
+ deployments = response.json().get('deployments', [])
212
+
213
+ # ์ƒํƒœ๊ฐ€ 'READY'์ด๊ณ  'url'์ด ์žˆ๋Š” ๋ฐฐํฌ๋งŒ ํ•„ํ„ฐ๋งํ•˜๊ณ  'javis1' ์ œ์™ธ
214
+ active_deployments = [
215
+ dep for dep in deployments
216
+ if dep.get('state') == 'READY' and
217
+ dep.get('url') and
218
+ 'javis1' not in dep.get('name', '').lower() # javis1 ์ œ์™ธ
219
+ ]
220
+
221
+ return active_deployments
222
+ except Exception as e:
223
+ print(f"Error fetching Vercel deployments: {str(e)}")
224
+ return []
225
+
226
+ def get_vercel_card(deployment, index):
227
+ """Generate HTML card for a Vercel deployment"""
228
+ # URL์—์„œ ์ฒซ 6๊ธ€์ž๋งŒ ์ถ”์ถœํ•˜์—ฌ vercel.app ๋„๋ฉ”์ธ ๊ตฌ์„ฑ
229
+ raw_url = deployment.get('url', '')
230
+ project_name = raw_url[:6] if len(raw_url) >= 6 else raw_url # ์ฒซ 6๊ธ€์ž๋งŒ ์ถ”์ถœ
231
+ url = f"{project_name}.vercel.app" # ์ƒˆ๋กœ์šด URL ํ˜•์‹ ์ ์šฉ
232
+
233
+ created = format_timestamp(deployment.get('created'))
234
+ name = deployment.get('name', 'Unnamed Project')
235
+ state = deployment.get('state', 'N/A')
236
+
237
+ bg_color = get_pastel_color(index + 20)
238
+
239
+ tech_emojis = ['โšก', '๐Ÿš€', '๐ŸŒŸ', 'โœจ', '๐Ÿ’ซ', '๐Ÿ”ฅ', '๐ŸŒˆ', '๐ŸŽฏ', '๐ŸŽจ', '๐Ÿ”ฎ']
240
+ random_emojis = random.sample(tech_emojis, 3)
241
+
242
+ return f"""
243
+ <div style='border: none;
244
+ padding: 25px;
245
+ margin: 15px;
246
+ border-radius: 20px;
247
+ background-color: {bg_color};
248
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
249
+ transition: all 0.3s ease-in-out;
250
+ position: relative;
251
+ overflow: hidden;'
252
+ onmouseover='this.style.transform="translateY(-5px) scale(1.02)"; this.style.boxShadow="0 8px 25px rgba(0,0,0,0.15)"'
253
+ onmouseout='this.style.transform="translateY(0) scale(1)"; this.style.boxShadow="0 4px 15px rgba(0,0,0,0.1)"'>
254
+ <div style='position: absolute; top: -15px; right: -15px; font-size: 100px; opacity: 0.1;'>
255
+ {random_emojis[0]}
256
+ </div>
257
+ <h3 style='color: #2d2d2d;
258
+ margin: 0 0 20px 0;
259
+ font-size: 1.4em;
260
+ display: flex;
261
+ align-items: center;
262
+ gap: 10px;'>
263
+ <span style='font-size: 1.3em'>{random_emojis[1]}</span>
264
+ <a href='https://{url}' target='_blank'
265
+ style='text-decoration: none; color: #2d2d2d;'>
266
+ {name}
267
+ </a>
268
+ <span style='font-size: 1.3em'>{random_emojis[2]}</span>
269
+ </h3>
270
+ <div style='margin: 15px 0; color: #444; background: rgba(255,255,255,0.5);
271
+ padding: 15px; border-radius: 12px;'>
272
+ <p style='margin: 8px 0;'>
273
+ <strong>Status:</strong> โœ… {state}
274
+ </p>
275
+ <p style='margin: 8px 0;'>
276
+ <strong>Created:</strong> ๐Ÿ“… {created}
277
+ </p>
278
+ <p style='margin: 8px 0;'>
279
+ <strong>URL:</strong> ๐Ÿ”— https://{url}
280
+ </p>
281
+ </div>
282
+ <div style='margin-top: 20px;'>
283
+ <a href='https://{url}' target='_blank'
284
+ style='background: linear-gradient(45deg, #0084ff, #00a3ff);
285
+ color: white;
286
+ padding: 10px 20px;
287
+ border-radius: 15px;
288
+ text-decoration: none;
289
+ display: inline-flex;
290
+ align-items: center;
291
+ gap: 8px;
292
+ font-weight: 500;
293
+ transition: all 0.3s;
294
+ box-shadow: 0 2px 8px rgba(0,132,255,0.3);'
295
+ onmouseover='this.style.transform="scale(1.05)"; this.style.boxShadow="0 4px 12px rgba(0,132,255,0.4)"'
296
+ onmouseout='this.style.transform="scale(1)"; this.style.boxShadow="0 2px 8px rgba(0,132,255,0.3)"'>
297
+ <span>View Deployment</span> ๐Ÿš€
298
+ </a>
299
+ </div>
300
+ </div>
301
+ """
302
+
303
+ # get_user_spaces ํ•จ์ˆ˜ ์ˆ˜์ •
304
+ def get_user_spaces():
305
+ # ๊ธฐ์กด Hugging Face ์ŠคํŽ˜์ด์Šค ๊ฐ€์ ธ์˜ค๊ธฐ
306
+ url = f"https://huggingface.co/api/spaces?author={USERNAME}&limit=500"
307
+ headers = {
308
+ "Accept": "application/json",
309
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
310
+ }
311
+
312
+ try:
313
+ # Hugging Face ์ŠคํŽ˜์ด์Šค ๊ฐ€์ ธ์˜ค๊ธฐ
314
+ response = requests.get(url, headers=headers)
315
+ spaces_data = response.json() if response.status_code == 200 else []
316
+
317
+ # ์ œ์™ธํ•  ์ŠคํŽ˜์ด์Šค ํ•„ํ„ฐ๋ง
318
+ user_spaces = [
319
+ space for space in spaces_data
320
+ if not should_exclude_space(space.get('id', '').split('/')[-1])
321
+ ]
322
+
323
+ # Vercel ๋ฐฐํฌ ๊ฐ€์ ธ์˜ค๊ธฐ
324
+ vercel_deployments = get_vercel_deployments()
325
+
326
+ html_content = f"""
327
+ <div style='padding: 20px; background-color: #f5f5f5;'>
328
+ <div style='margin-bottom: 20px;'>
329
+ <h2 style='color: #333; margin: 0 0 5px 0;'>๊ณต๊ฐœ ๊ฐค๋Ÿฌ๋ฆฌ(์ƒ์„ฑ Web/App) by MOUSE</h2>
330
+ <p style='color: #666; margin: 0 0 15px 0; font-size: 0.9em;'>
331
+ ํ”„๋กฌํ”„ํŠธ๋งŒ์œผ๋กœ ๋‚˜๋งŒ์˜ ์›น์„œ๋น„์Šค๋ฅผ ์ฆ‰์‹œ ์ƒ์„ฑํ•˜๋Š” MOUSE
332
+ <a href='https://openfree-mouse.hf.space' target='_blank'
333
+ style='color: #0084ff; text-decoration: none;'>
334
+ https://openfree-mouse.hf.space
335
+ </a>
336
+ </p>
337
+ <p style='color: #666; margin: 0;'>
338
+ Found {len(vercel_deployments)} Vercel deployments and {len(user_spaces)} Hugging Face spaces
339
+ </p>
340
+ </div>
341
+
342
+ <!-- Vercel Deployments (๋จผ์ € ํ‘œ์‹œ) -->
343
+ <h3 style='color: #333; margin: 20px 0;'>โšก Vercel Deployments</h3>
344
+ <div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;'>
345
+ {"".join(get_vercel_card(dep, idx) for idx, dep in enumerate(vercel_deployments))}
346
+ </div>
347
+
348
+ <!-- Hugging Face Spaces (๋‚˜์ค‘์— ํ‘œ์‹œ) -->
349
+ <h3 style='color: #333; margin: 20px 0;'>๐Ÿค— Hugging Face Spaces</h3>
350
+ <div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;'>
351
+ {"".join(get_space_card(space, idx) for idx, space in enumerate(user_spaces))}
352
+ </div>
353
+ </div>
354
+ """
355
+
356
+ return html_content
357
+
358
+ except Exception as e:
359
+ print(f"Error: {str(e)}")
360
+ return f"""
361
+ <div style='padding: 20px; text-align: center; color: #666;'>
362
+ <h2>Error occurred while fetching spaces</h2>
363
+ <p>Error details: {str(e)}</p>
364
+ <p>Please try again later.</p>
365
+ </div>
366
+ """
367
+
368
+ # Creating the Gradio interface
369
+ demo = gr.Blocks()
370
+
371
+ with demo:
372
+ html_output = gr.HTML(value=get_user_spaces()) # ์ดˆ๊ธฐ ๋กœ๋“œ ์‹œ ์ง์ ‘ ํ•จ์ˆ˜ ํ˜ธ์ถœ
373
+
374
+ if __name__ == "__main__":
375
+ demo.launch()