ginipick commited on
Commit
428a5c8
ยท
verified ยท
1 Parent(s): 8e9ec52

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +183 -23
app.py CHANGED
@@ -75,33 +75,56 @@ def process_url_for_iframe(url):
75
  """URL์„ iframe์— ํ‘œ์‹œํ•˜๊ธฐ ์ ํ•ฉํ•œ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค."""
76
  # ํ—ˆ๊น…ํŽ˜์ด์Šค URL ํŒจํ„ด ๊ฐ์ง€
77
  is_huggingface = False
 
78
 
79
- # huggingface.co/spaces ํŒจํ„ด ์ฒ˜๋ฆฌ
80
  if "huggingface.co/spaces" in url:
81
  is_huggingface = True
 
 
 
 
82
  try:
83
- # URL์—์„œ owner์™€ name ์ถ”์ถœ
84
- parts = url.split('/spaces/')[1].split('/')
85
- owner = parts[0]
86
- name = parts[1] if len(parts) > 1 else ""
87
-
88
- # ํŠน์ˆ˜ ๋ฌธ์ž ์ฒ˜๋ฆฌ ๋ฐ ์†Œ๋ฌธ์ž ๋ณ€ํ™˜
89
- name = name.replace('.', '-').replace('_', '-').lower()
90
- owner = owner.lower()
91
-
92
- # ์ƒˆ URL ํ˜•์‹ ์ ์šฉ
93
- return f"https://{owner}-{name}.hf.space", is_huggingface
94
- except:
95
- # ์˜ค๋ฅ˜ ๋ฐœ์ƒ์‹œ ์›๋ž˜ URL ์‚ฌ์šฉ
96
- return url, is_huggingface
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
- # ์ด๋ฏธ .hf.space ๋„๋ฉ”์ธ์ธ ๊ฒฝ์šฐ
99
  elif ".hf.space" in url:
100
  is_huggingface = True
101
- return url, is_huggingface
 
 
 
 
102
 
103
- # ์ผ๋ฐ˜ URL์€ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜
104
- return url, is_huggingface
 
105
 
106
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 6. HTML ๊ทธ๋ฆฌ๋“œ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
107
  def html(cards, pg, total):
@@ -248,28 +271,163 @@ def html(cards, pg, total):
248
  height: 350px; /* Adjusted for small screens */
249
  }
250
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  </style>"""
252
 
253
- h = css + """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  <div class="container">
255
  <div class="grid">
256
  """
257
 
258
- for c in cards:
259
  date = datetime.datetime.fromtimestamp(int(c["ts"])).strftime("%Y-%m-%d")
260
 
261
  # URL ์ฒ˜๋ฆฌ: ํ—ˆ๊น…ํŽ˜์ด์Šค URL์ธ ๊ฒฝ์šฐ ํŠน๋ณ„ ์ฒ˜๋ฆฌ
262
  url = c['url']
263
- iframe_url, is_huggingface = process_url_for_iframe(url)
264
 
265
  # ํ—ˆ๊น…ํŽ˜์ด์Šค URL์— ํŠน๋ณ„ ํด๋ž˜์Šค ์ถ”๊ฐ€
266
  frame_class = "frame huggingface" if is_huggingface else "frame"
267
 
 
 
 
 
 
 
 
 
268
  h += f"""
269
  <div class="card">
270
  <div class="hdr"><p class="ttl">{c['title']}</p><p class="date">{date}</p></div>
271
  <div class="{frame_class}">
272
  <iframe
 
273
  src="{iframe_url}"
274
  loading="lazy"
275
  frameborder="0"
@@ -277,7 +435,9 @@ def html(cards, pg, total):
277
  height="100%"
278
  allowfullscreen="true"
279
  allow="accelerometer; camera; encrypted-media; gyroscope; geolocation;"
280
- sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads">
 
 
281
  </iframe>
282
  </div>
283
  <div class="foot"><a class="link" href="{url}" target="_blank">์›๋ณธโ†—</a></div>
 
75
  """URL์„ iframe์— ํ‘œ์‹œํ•˜๊ธฐ ์ ํ•ฉํ•œ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค."""
76
  # ํ—ˆ๊น…ํŽ˜์ด์Šค URL ํŒจํ„ด ๊ฐ์ง€
77
  is_huggingface = False
78
+ embed_urls = []
79
 
80
+ # 1. huggingface.co/spaces ํŒจํ„ด ์ฒ˜๋ฆฌ
81
  if "huggingface.co/spaces" in url:
82
  is_huggingface = True
83
+
84
+ # ๊ธฐ๋ณธ URL ์ •๊ทœํ™”
85
+ base_url = url.rstrip("/")
86
+
87
  try:
88
+ # /spaces/ ์ดํ›„์˜ ๊ฒฝ๋กœ ์ถ”์ถœ
89
+ if "/spaces/" in base_url:
90
+ path = base_url.split("/spaces/")[1]
91
+ parts = path.split("/")
92
+ owner = parts[0]
93
+
94
+ # name ๋ถ€๋ถ„ ์ถ”์ถœ
95
+ if len(parts) > 1:
96
+ name = parts[1]
97
+
98
+ # ํŠน์ˆ˜ ๋ฌธ์ž ๋ณ€ํ™˜
99
+ clean_name = name.replace('.', '-').replace('_', '-').lower()
100
+ clean_owner = owner.lower()
101
+
102
+ # ์—ฌ๋Ÿฌ ํฌ๋งท์˜ URL์„ ์‹œ๋„ํ•˜๊ธฐ ์œ„ํ•ด ๋ชฉ๋ก์— ์ถ”๊ฐ€
103
+ embed_urls.append(f"https://huggingface.co/spaces/{owner}/{name}/embed") # ๊ณต์‹ embed URL
104
+ embed_urls.append(f"https://{clean_owner}-{clean_name}.hf.space") # ์ง์ ‘ ๋„๋ฉ”์ธ ์ ‘๊ทผ
105
+ else:
106
+ # owner๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ ๊ณต์‹ URL ์‚ฌ์šฉ
107
+ embed_urls.append(f"https://huggingface.co/spaces/{owner}/embed")
108
+ except Exception as e:
109
+ print(f"ํ—ˆ๊น…ํŽ˜์ด์Šค URL ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {e}")
110
+ # ๊ธฐ๋ณธ embed URL ์‹œ๋„
111
+ if not base_url.endswith("/embed"):
112
+ embed_urls.append(f"{base_url}/embed")
113
+ else:
114
+ embed_urls.append(base_url)
115
 
116
+ # 2. .hf.space ๋„๋ฉ”์ธ ์ฒ˜๋ฆฌ
117
  elif ".hf.space" in url:
118
  is_huggingface = True
119
+ embed_urls.append(url) # ํ˜„์žฌ URL ๊ทธ๋Œ€๋กœ ์‹œ๋„
120
+
121
+ # 3. ์ผ๋ฐ˜ URL์€ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜
122
+ else:
123
+ return url, is_huggingface, []
124
 
125
+ # ์ตœ์ข… URL๊ณผ ํ•จ๊ป˜ ์‹œ๋„ํ•  ๋Œ€์ฒด URL ๋ชฉ๋ก ๋ฐ˜ํ™˜
126
+ primary_url = embed_urls[0] if embed_urls else url
127
+ return primary_url, is_huggingface, embed_urls[1:] if len(embed_urls) > 1 else []
128
 
129
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 6. HTML ๊ทธ๋ฆฌ๋“œ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
130
  def html(cards, pg, total):
 
271
  height: 350px; /* Adjusted for small screens */
272
  }
273
  }
274
+
275
+ /* ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๊ด€๋ จ CSS */
276
+ .error-message {
277
+ position: absolute;
278
+ top: 0;
279
+ left: 0;
280
+ width: 100%;
281
+ height: 100%;
282
+ display: flex;
283
+ flex-direction: column;
284
+ justify-content: center;
285
+ align-items: center;
286
+ background-color: rgba(255, 255, 255, 0.9);
287
+ z-index: 20;
288
+ padding: 20px;
289
+ text-align: center;
290
+ }
291
+ .error-icon {
292
+ font-size: 48px;
293
+ margin-bottom: 15px;
294
+ }
295
+ .error-text {
296
+ font-weight: bold;
297
+ margin-bottom: 15px;
298
+ }
299
+ .error-link {
300
+ display: inline-block;
301
+ padding: 8px 16px;
302
+ background-color: #f0f0f7;
303
+ border-radius: 4px;
304
+ color: #4a6dd8;
305
+ font-weight: bold;
306
+ text-decoration: none;
307
+ transition: background-color 0.2s;
308
+ }
309
+ .error-link:hover {
310
+ background-color: #e0e0f0;
311
+ }
312
  </style>"""
313
 
314
+ js = """
315
+ <script>
316
+ // ํ—ˆ๊น…ํŽ˜์ด์Šค iframe ๋กœ๋”ฉ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ
317
+ function handleIframeError(iframeId, alternateUrls, originalUrl) {
318
+ const iframe = document.getElementById(iframeId);
319
+ if (!iframe) return;
320
+
321
+ // iframe ๋กœ๋“œ ์‹คํŒจ ์ฒ˜๋ฆฌ
322
+ iframe.onerror = function() {
323
+ tryNextUrl(iframeId, alternateUrls, originalUrl);
324
+ };
325
+
326
+ // onload ์ด๋ฒคํŠธ์—์„œ ๋กœ๋“œ ์‹คํŒจ ํ™•์ธ
327
+ iframe.onload = function() {
328
+ try {
329
+ // iframe ๋‚ด์šฉ์— ์ ‘๊ทผ ์‹œ๋„ (cross-origin ์ œํ•œ์œผ๋กœ ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Œ)
330
+ const iframeContent = iframe.contentWindow.document;
331
+ console.log("iframe loaded successfully: " + iframeId);
332
+ } catch (e) {
333
+ // cross-origin ์˜ค๋ฅ˜๋Š” ๋ฌด์‹œ (์ •์ƒ์ ์ธ ์ƒํ™ฉ์ผ ์ˆ˜ ์žˆ์Œ)
334
+ console.log("Cross-origin iframe loaded (expected): " + iframeId);
335
+ }
336
+
337
+ // iframe์ด ์ œ๋Œ€๋กœ ํ‘œ์‹œ๋˜๋Š”์ง€ 10์ดˆ ํ›„ ํ™•์ธ
338
+ setTimeout(function() {
339
+ if (iframe.offsetWidth === 0 || iframe.offsetHeight === 0) {
340
+ console.log("iframe not visible, trying alternate URL: " + iframeId);
341
+ tryNextUrl(iframeId, alternateUrls, originalUrl);
342
+ } else {
343
+ console.log("iframe appears to be visible: " + iframeId);
344
+ }
345
+ }, 5000);
346
+ };
347
+ }
348
+
349
+ // ๋Œ€์ฒด URL ์‹œ๋„
350
+ function tryNextUrl(iframeId, alternateUrls, originalUrl) {
351
+ const iframe = document.getElementById(iframeId);
352
+ if (!iframe) return;
353
+
354
+ // ๋Œ€์ฒด URL์ด ์žˆ์œผ๋ฉด ์‹œ๋„
355
+ if (alternateUrls && alternateUrls.length > 0) {
356
+ const nextUrl = alternateUrls.shift();
357
+ console.log("Trying alternate URL: " + nextUrl);
358
+ iframe.src = nextUrl;
359
+
360
+ // ๋Œ€์ฒด URL๋กœ ๋‹ค์‹œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ์„ค์ •
361
+ handleIframeError(iframeId, alternateUrls, originalUrl);
362
+ } else {
363
+ // ๋ชจ๋“  URL ์‹œ๋„ ์‹คํŒจ ์‹œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
364
+ console.log("All URLs failed, showing error for: " + iframeId);
365
+ const container = iframe.parentNode;
366
+
367
+ // ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
368
+ const errorDiv = document.createElement('div');
369
+ errorDiv.className = 'error-message';
370
+
371
+ errorDiv.innerHTML = `
372
+ <div class="error-icon">โš ๏ธ</div>
373
+ <p class="error-text">์ฝ˜ํ…์ธ ๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค</p>
374
+ <a href="${originalUrl}" target="_blank" class="error-link">
375
+ ์›๋ณธ ํŽ˜์ด์ง€์—์„œ ์—ด๊ธฐ
376
+ </a>
377
+ `;
378
+
379
+ // iframe ์ˆจ๊ธฐ๊ณ  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
380
+ iframe.style.display = 'none';
381
+ container.appendChild(errorDiv);
382
+ }
383
+ }
384
+
385
+ // ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ ๋ชจ๋“  ํ—ˆ๊น…ํŽ˜์ด์Šค iframe ์ฒ˜๋ฆฌ
386
+ window.addEventListener('load', function() {
387
+ const iframes = document.querySelectorAll('.huggingface iframe');
388
+ iframes.forEach(function(iframe) {
389
+ const id = iframe.id;
390
+ const alternateUrlsStr = iframe.getAttribute('data-alternate-urls');
391
+ const alternateUrls = alternateUrlsStr ? alternateUrlsStr.split(',').filter(url => url) : [];
392
+ const originalUrl = iframe.getAttribute('data-original-url') || iframe.src;
393
+
394
+ if (id && alternateUrls.length > 0) {
395
+ handleIframeError(id, alternateUrls, originalUrl);
396
+ }
397
+ });
398
+ });
399
+ </script>
400
+ """
401
+
402
+ h = css + js + """
403
  <div class="container">
404
  <div class="grid">
405
  """
406
 
407
+ for idx, c in enumerate(cards):
408
  date = datetime.datetime.fromtimestamp(int(c["ts"])).strftime("%Y-%m-%d")
409
 
410
  # URL ์ฒ˜๋ฆฌ: ํ—ˆ๊น…ํŽ˜์ด์Šค URL์ธ ๊ฒฝ์šฐ ํŠน๋ณ„ ์ฒ˜๋ฆฌ
411
  url = c['url']
412
+ iframe_url, is_huggingface, alt_urls = process_url_for_iframe(url)
413
 
414
  # ํ—ˆ๊น…ํŽ˜์ด์Šค URL์— ํŠน๋ณ„ ํด๋ž˜์Šค ์ถ”๊ฐ€
415
  frame_class = "frame huggingface" if is_huggingface else "frame"
416
 
417
+ # ๊ณ ์œ  ID ์ƒ์„ฑ
418
+ iframe_id = f"iframe-{idx}-{hash(url) % 10000}"
419
+
420
+ # ๋Œ€์ฒด URL์„ ๋ฐ์ดํ„ฐ ์†์„ฑ์œผ๋กœ ์ถ”๊ฐ€
421
+ alternate_urls_attr = ""
422
+ if alt_urls:
423
+ alternate_urls_attr = f'data-alternate-urls="{",".join(alt_urls)}"'
424
+
425
  h += f"""
426
  <div class="card">
427
  <div class="hdr"><p class="ttl">{c['title']}</p><p class="date">{date}</p></div>
428
  <div class="{frame_class}">
429
  <iframe
430
+ id="{iframe_id}"
431
  src="{iframe_url}"
432
  loading="lazy"
433
  frameborder="0"
 
435
  height="100%"
436
  allowfullscreen="true"
437
  allow="accelerometer; camera; encrypted-media; gyroscope; geolocation;"
438
+ sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"
439
+ data-original-url="{url}"
440
+ {alternate_urls_attr}>
441
  </iframe>
442
  </div>
443
  <div class="foot"><a class="link" href="{url}" target="_blank">์›๋ณธโ†—</a></div>