Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,78 +1,41 @@
|
|
| 1 |
from flask import Flask, render_template, request, jsonify, session
|
| 2 |
-
import requests
|
| 3 |
import os
|
| 4 |
from datetime import timedelta
|
| 5 |
-
import json
|
| 6 |
|
| 7 |
app = Flask(__name__)
|
| 8 |
app.secret_key = os.urandom(24)
|
| 9 |
app.permanent_session_lifetime = timedelta(days=7)
|
| 10 |
|
| 11 |
-
# Hugging Face URL ๋ชฉ๋ก
|
|
|
|
| 12 |
HUGGINGFACE_URLS = [
|
| 13 |
-
"https://huggingface.co/spaces/ginipick/Tech_Hangman_Game",
|
| 14 |
-
"https://huggingface.co/spaces/openfree/deepseek_r1_API",
|
| 15 |
-
"https://huggingface.co/spaces/ginipick/open_Deep-Research",
|
| 16 |
-
"https://huggingface.co/spaces/aiqmaster/open-deep-research",
|
| 17 |
-
"https://huggingface.co/spaces/seawolf2357/DeepSeek-R1-32b-search",
|
| 18 |
-
"https://huggingface.co/spaces/ginigen/LLaDA",
|
| 19 |
-
"https://huggingface.co/spaces/VIDraft/PHI4-Multimodal",
|
| 20 |
-
"https://huggingface.co/spaces/ginigen/Ovis2-8B",
|
| 21 |
-
"https://huggingface.co/spaces/ginigen/Graph-Mind",
|
| 22 |
-
"https://huggingface.co/spaces/ginigen/Workflow-Canvas",
|
| 23 |
-
"https://huggingface.co/spaces/ginigen/Design",
|
| 24 |
-
"https://huggingface.co/spaces/ginigen/Diagram",
|
| 25 |
-
"https://huggingface.co/spaces/ginigen/Mockup",
|
| 26 |
-
"https://huggingface.co/spaces/ginigen/Infographic",
|
| 27 |
-
"https://huggingface.co/spaces/ginigen/Flowchart",
|
| 28 |
-
"https://huggingface.co/spaces/aiqcamp/FLUX-Vision",
|
| 29 |
-
"https://huggingface.co/spaces/ginigen/VoiceClone-TTS",
|
| 30 |
-
"https://huggingface.co/spaces/openfree/Perceptron-Network",
|
| 31 |
-
"https://huggingface.co/spaces/openfree/Article-Generator",
|
| 32 |
]
|
| 33 |
|
| 34 |
-
# URL์์ ๋ชจ๋ธ/์คํ์ด์ค ์ ๋ณด ์ถ์ถ
|
| 35 |
-
def extract_model_info(url):
|
| 36 |
-
parts = url.split('/')
|
| 37 |
-
if len(parts) < 6:
|
| 38 |
-
return None
|
| 39 |
-
|
| 40 |
-
if parts[3] == 'spaces' or parts[3] == 'models':
|
| 41 |
-
return {
|
| 42 |
-
'type': parts[3],
|
| 43 |
-
'owner': parts[4],
|
| 44 |
-
'repo': parts[5],
|
| 45 |
-
'full_id': f"{parts[4]}/{parts[5]}"
|
| 46 |
-
}
|
| 47 |
-
elif len(parts) >= 5:
|
| 48 |
-
return {
|
| 49 |
-
'type': 'models',
|
| 50 |
-
'owner': parts[3],
|
| 51 |
-
'repo': parts[4],
|
| 52 |
-
'full_id': f"{parts[3]}/{parts[4]}"
|
| 53 |
-
}
|
| 54 |
-
|
| 55 |
-
return None
|
| 56 |
-
|
| 57 |
# URL์ ๋ง์ง๋ง ๋ถ๋ถ์ ์ ๋ชฉ์ผ๋ก ์ถ์ถ
|
| 58 |
def extract_title(url):
|
| 59 |
parts = url.split("/")
|
| 60 |
title = parts[-1] if parts else ""
|
| 61 |
return title.replace("_", " ").replace("-", " ")
|
| 62 |
|
| 63 |
-
# ํ๊น
ํ์ด์ค ์ฌ์ฉ์ ์ธ์ฆ
|
| 64 |
-
def validate_token(token):
|
| 65 |
-
headers = {"Authorization": f"Bearer {token}"}
|
| 66 |
-
|
| 67 |
-
try:
|
| 68 |
-
response = requests.get("https://huggingface.co/api/whoami-v2", headers=headers)
|
| 69 |
-
if response.ok:
|
| 70 |
-
return True, response.json()
|
| 71 |
-
except Exception as e:
|
| 72 |
-
print(f"ํ ํฐ ๊ฒ์ฆ ์ค๋ฅ: {e}")
|
| 73 |
-
|
| 74 |
-
return False, None
|
| 75 |
-
|
| 76 |
@app.route('/')
|
| 77 |
def home():
|
| 78 |
return render_template('index.html')
|
|
@@ -84,30 +47,16 @@ def login():
|
|
| 84 |
if not token:
|
| 85 |
return jsonify({'success': False, 'message': 'ํ ํฐ์ ์
๋ ฅํด์ฃผ์ธ์.'})
|
| 86 |
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
if not is_valid or not user_info:
|
| 90 |
return jsonify({'success': False, 'message': '์ ํจํ์ง ์์ ํ ํฐ์
๋๋ค.'})
|
| 91 |
|
| 92 |
-
# ์ฌ์ฉ์
|
| 93 |
-
username =
|
| 94 |
-
if 'name' in user_info:
|
| 95 |
-
username = user_info['name']
|
| 96 |
-
elif 'user' in user_info and 'username' in user_info['user']:
|
| 97 |
-
username = user_info['user']['username']
|
| 98 |
-
elif 'username' in user_info:
|
| 99 |
-
username = user_info['username']
|
| 100 |
-
else:
|
| 101 |
-
username = '์ธ์ฆ๋ ์ฌ์ฉ์'
|
| 102 |
|
| 103 |
# ์ธ์
์ ์ ์ฅ
|
| 104 |
-
session['token'] = token
|
| 105 |
session['username'] = username
|
| 106 |
|
| 107 |
-
# ์ฌ์ฉ์๊ฐ ์ข์์ํ URL ์ํ๋ฅผ ์ธ์
์ ์ด๊ธฐํ
|
| 108 |
-
if 'liked_urls' not in session:
|
| 109 |
-
session['liked_urls'] = {}
|
| 110 |
-
|
| 111 |
return jsonify({
|
| 112 |
'success': True,
|
| 113 |
'username': username
|
|
@@ -115,30 +64,20 @@ def login():
|
|
| 115 |
|
| 116 |
@app.route('/api/logout', methods=['POST'])
|
| 117 |
def logout():
|
| 118 |
-
session.pop('token', None)
|
| 119 |
session.pop('username', None)
|
| 120 |
-
session.pop('liked_urls', None)
|
| 121 |
return jsonify({'success': True})
|
| 122 |
|
| 123 |
@app.route('/api/urls', methods=['GET'])
|
| 124 |
def get_urls():
|
| 125 |
results = []
|
| 126 |
-
for
|
|
|
|
|
|
|
| 127 |
title = extract_title(url)
|
| 128 |
-
model_info = extract_model_info(url)
|
| 129 |
-
|
| 130 |
-
if not model_info:
|
| 131 |
-
continue
|
| 132 |
-
|
| 133 |
-
# ์ฌ์ฉ์์ ์ข์์ ์ํ ํ์ธ
|
| 134 |
-
is_liked = False
|
| 135 |
-
if 'liked_urls' in session and url in session['liked_urls']:
|
| 136 |
-
is_liked = True
|
| 137 |
|
| 138 |
results.append({
|
| 139 |
'url': url,
|
| 140 |
'title': title,
|
| 141 |
-
'model_info': model_info,
|
| 142 |
'is_liked': is_liked
|
| 143 |
})
|
| 144 |
|
|
@@ -155,38 +94,19 @@ def toggle_like():
|
|
| 155 |
if not url:
|
| 156 |
return jsonify({'success': False, 'message': 'URL์ด ํ์ํฉ๋๋ค.'})
|
| 157 |
|
| 158 |
-
#
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
# ์ธ์
์ ์ข์์ ์ ๋ณด ์
๋ฐ์ดํธ
|
| 172 |
-
session['liked_urls'] = liked_urls
|
| 173 |
-
|
| 174 |
-
return jsonify({
|
| 175 |
-
'success': True,
|
| 176 |
-
'is_liked': is_liked,
|
| 177 |
-
'message': message
|
| 178 |
-
})
|
| 179 |
-
|
| 180 |
-
@app.route('/api/get-likes', methods=['GET'])
|
| 181 |
-
def get_likes():
|
| 182 |
-
if 'username' not in session:
|
| 183 |
-
return jsonify({'success': False, 'message': '๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค.'})
|
| 184 |
-
|
| 185 |
-
liked_urls = session.get('liked_urls', {})
|
| 186 |
-
return jsonify({
|
| 187 |
-
'success': True,
|
| 188 |
-
'liked_urls': liked_urls
|
| 189 |
-
})
|
| 190 |
|
| 191 |
@app.route('/api/session-status', methods=['GET'])
|
| 192 |
def session_status():
|
|
@@ -560,7 +480,6 @@ if __name__ == '__main__':
|
|
| 560 |
// ์ ํ๋ฆฌ์ผ์ด์
์ํ
|
| 561 |
const state = {
|
| 562 |
username: null,
|
| 563 |
-
likedURLs: {},
|
| 564 |
allURLs: [],
|
| 565 |
isLoading: false,
|
| 566 |
viewMode: 'all' // 'all' ๋๋ 'liked'
|
|
@@ -596,7 +515,7 @@ if __name__ == '__main__':
|
|
| 596 |
// ์ข์์ ํต๊ณ ์
๋ฐ์ดํธ
|
| 597 |
function updateLikeStats() {
|
| 598 |
const totalCount = state.allURLs.length;
|
| 599 |
-
const likedCount =
|
| 600 |
|
| 601 |
elements.totalUrlCount.textContent = totalCount;
|
| 602 |
elements.likedUrlCount.textContent = likedCount;
|
|
@@ -615,9 +534,6 @@ if __name__ == '__main__':
|
|
| 615 |
elements.loggedInSection.style.display = 'block';
|
| 616 |
elements.likeStatus.style.display = 'block';
|
| 617 |
|
| 618 |
-
// ์ข์์ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ
|
| 619 |
-
await getLikedUrls();
|
| 620 |
-
|
| 621 |
// URL ๋ชฉ๋ก ๋ก๋
|
| 622 |
loadUrls();
|
| 623 |
}
|
|
@@ -626,23 +542,6 @@ if __name__ == '__main__':
|
|
| 626 |
}
|
| 627 |
}
|
| 628 |
|
| 629 |
-
// ์ข์์ URL ๊ฐ์ ธ์ค๊ธฐ
|
| 630 |
-
async function getLikedUrls() {
|
| 631 |
-
try {
|
| 632 |
-
const response = await fetch('/api/get-likes');
|
| 633 |
-
const data = await handleApiResponse(response);
|
| 634 |
-
|
| 635 |
-
if (data.success) {
|
| 636 |
-
state.likedURLs = data.liked_urls || {};
|
| 637 |
-
return true;
|
| 638 |
-
}
|
| 639 |
-
} catch (error) {
|
| 640 |
-
console.error('์ข์์ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ ์ค๋ฅ:', error);
|
| 641 |
-
}
|
| 642 |
-
|
| 643 |
-
return false;
|
| 644 |
-
}
|
| 645 |
-
|
| 646 |
// ๋ก๊ทธ์ธ ์ฒ๋ฆฌ
|
| 647 |
async function login(token) {
|
| 648 |
if (!token.trim()) {
|
|
@@ -673,9 +572,6 @@ if __name__ == '__main__':
|
|
| 673 |
|
| 674 |
showMessage(`${state.username}๋์ผ๋ก ๋ก๊ทธ์ธ๋์์ต๋๋ค.`);
|
| 675 |
|
| 676 |
-
// ์ข์์ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ
|
| 677 |
-
await getLikedUrls();
|
| 678 |
-
|
| 679 |
// URL ๋ชฉ๋ก ๋ก๋
|
| 680 |
loadUrls();
|
| 681 |
} else {
|
|
@@ -702,7 +598,6 @@ if __name__ == '__main__':
|
|
| 702 |
|
| 703 |
if (data.success) {
|
| 704 |
state.username = null;
|
| 705 |
-
state.likedURLs = {};
|
| 706 |
state.allURLs = [];
|
| 707 |
|
| 708 |
elements.currentUser.textContent = '๋ก๊ทธ์ธ๋์ง ์์';
|
|
@@ -735,13 +630,6 @@ if __name__ == '__main__':
|
|
| 735 |
// URL ๋ฐ ์ข์์ ์ํ ์ ์ฅ
|
| 736 |
state.allURLs = urls;
|
| 737 |
|
| 738 |
-
// ์๋ฒ์์ ๋ฐ์ ์ข์์ ์ํ ์
๋ฐ์ดํธ
|
| 739 |
-
urls.forEach(item => {
|
| 740 |
-
if (item.is_liked) {
|
| 741 |
-
state.likedURLs[item.url] = true;
|
| 742 |
-
}
|
| 743 |
-
});
|
| 744 |
-
|
| 745 |
// ํํฐ๋ง ๋ฐ ๋ ๋๋ง
|
| 746 |
filterAndRenderCards();
|
| 747 |
|
|
@@ -761,10 +649,10 @@ if __name__ == '__main__':
|
|
| 761 |
|
| 762 |
// ํํฐ๋ง ์ ์ฉ
|
| 763 |
const filteredUrls = state.allURLs.filter(item => {
|
| 764 |
-
const { url, title } = item;
|
| 765 |
|
| 766 |
// ์ข์์ ํํฐ๋ง (์ข์์๋ง ๋ณด๊ธฐ ๋ชจ๋)
|
| 767 |
-
if (state.viewMode === 'liked' && !
|
| 768 |
return false;
|
| 769 |
}
|
| 770 |
|
|
@@ -800,23 +688,34 @@ if __name__ == '__main__':
|
|
| 800 |
const data = await handleApiResponse(response);
|
| 801 |
|
| 802 |
if (data.success) {
|
| 803 |
-
//
|
| 804 |
-
|
| 805 |
-
|
| 806 |
-
|
| 807 |
-
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
|
| 818 |
-
|
| 819 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 820 |
}
|
| 821 |
|
| 822 |
showMessage(data.message);
|
|
@@ -853,12 +752,11 @@ if __name__ == '__main__':
|
|
| 853 |
}
|
| 854 |
|
| 855 |
urls.forEach(item => {
|
| 856 |
-
const { url, title } = item;
|
| 857 |
-
const isLiked = state.likedURLs[url] || false;
|
| 858 |
|
| 859 |
// ์นด๋ ์์ฑ
|
| 860 |
const card = document.createElement('div');
|
| 861 |
-
card.className = `card ${
|
| 862 |
|
| 863 |
// ์นด๋ ํค๋
|
| 864 |
const cardHeader = document.createElement('div');
|
|
@@ -874,18 +772,16 @@ if __name__ == '__main__':
|
|
| 874 |
|
| 875 |
// URL ๋งํฌ
|
| 876 |
const linkEl = document.createElement('a');
|
| 877 |
-
|
| 878 |
-
|
| 879 |
-
linkEl.href = url;
|
| 880 |
linkEl.textContent = url;
|
| 881 |
linkEl.target = '_blank';
|
| 882 |
card.appendChild(linkEl);
|
| 883 |
|
| 884 |
// ์ข์์ ๋ฒํผ
|
| 885 |
const likeBtn = document.createElement('button');
|
| 886 |
-
likeBtn.className = `like-button ${
|
| 887 |
likeBtn.innerHTML = 'โฅ';
|
| 888 |
-
likeBtn.title =
|
| 889 |
|
| 890 |
likeBtn.addEventListener('click', (e) => {
|
| 891 |
e.preventDefault();
|
|
@@ -895,7 +791,7 @@ linkEl.href = url;
|
|
| 895 |
card.appendChild(likeBtn);
|
| 896 |
|
| 897 |
// ์ข์์ ๋ฐฐ์ง (์ข์์ ์ํ์ผ ๋๋ง)
|
| 898 |
-
if (
|
| 899 |
const likeBadge = document.createElement('div');
|
| 900 |
likeBadge.className = 'like-badge';
|
| 901 |
likeBadge.textContent = '์ข์์';
|
|
@@ -919,7 +815,7 @@ linkEl.href = url;
|
|
| 919 |
filterAndRenderCards();
|
| 920 |
}
|
| 921 |
|
| 922 |
-
|
| 923 |
elements.loginButton.addEventListener('click', () => {
|
| 924 |
login(elements.tokenInput.value);
|
| 925 |
});
|
|
@@ -952,4 +848,4 @@ linkEl.href = url;
|
|
| 952 |
''')
|
| 953 |
|
| 954 |
# ํ๊น
ํ์ด์ค ์คํ์ด์ค์์๋ 7860 ํฌํธ ์ฌ์ฉ
|
| 955 |
-
app.run(host='0.0.0.0', port=7860)
|
|
|
|
| 1 |
from flask import Flask, render_template, request, jsonify, session
|
|
|
|
| 2 |
import os
|
| 3 |
from datetime import timedelta
|
|
|
|
| 4 |
|
| 5 |
app = Flask(__name__)
|
| 6 |
app.secret_key = os.urandom(24)
|
| 7 |
app.permanent_session_lifetime = timedelta(days=7)
|
| 8 |
|
| 9 |
+
# Hugging Face URL ๋ชฉ๋ก - ์ผ๋ถ URL์ ๋ฏธ๋ฆฌ ์ข์์ ์ํ๋ก ์ค์
|
| 10 |
+
# 'is_liked'๋ฅผ true๋ก ์ค์ ํ URL์ ํญ์ ์ข์์ ์ํ๋ก ํ์๋จ
|
| 11 |
HUGGINGFACE_URLS = [
|
| 12 |
+
{"url": "https://huggingface.co/spaces/ginipick/Tech_Hangman_Game", "is_liked": True},
|
| 13 |
+
{"url": "https://huggingface.co/spaces/openfree/deepseek_r1_API", "is_liked": False},
|
| 14 |
+
{"url": "https://huggingface.co/spaces/ginipick/open_Deep-Research", "is_liked": True},
|
| 15 |
+
{"url": "https://huggingface.co/spaces/aiqmaster/open-deep-research", "is_liked": False},
|
| 16 |
+
{"url": "https://huggingface.co/spaces/seawolf2357/DeepSeek-R1-32b-search", "is_liked": True},
|
| 17 |
+
{"url": "https://huggingface.co/spaces/ginigen/LLaDA", "is_liked": False},
|
| 18 |
+
{"url": "https://huggingface.co/spaces/VIDraft/PHI4-Multimodal", "is_liked": True},
|
| 19 |
+
{"url": "https://huggingface.co/spaces/ginigen/Ovis2-8B", "is_liked": False},
|
| 20 |
+
{"url": "https://huggingface.co/spaces/ginigen/Graph-Mind", "is_liked": True},
|
| 21 |
+
{"url": "https://huggingface.co/spaces/ginigen/Workflow-Canvas", "is_liked": False},
|
| 22 |
+
{"url": "https://huggingface.co/spaces/ginigen/Design", "is_liked": True},
|
| 23 |
+
{"url": "https://huggingface.co/spaces/ginigen/Diagram", "is_liked": False},
|
| 24 |
+
{"url": "https://huggingface.co/spaces/ginigen/Mockup", "is_liked": True},
|
| 25 |
+
{"url": "https://huggingface.co/spaces/ginigen/Infographic", "is_liked": False},
|
| 26 |
+
{"url": "https://huggingface.co/spaces/ginigen/Flowchart", "is_liked": True},
|
| 27 |
+
{"url": "https://huggingface.co/spaces/aiqcamp/FLUX-Vision", "is_liked": False},
|
| 28 |
+
{"url": "https://huggingface.co/spaces/ginigen/VoiceClone-TTS", "is_liked": True},
|
| 29 |
+
{"url": "https://huggingface.co/spaces/openfree/Perceptron-Network", "is_liked": False},
|
| 30 |
+
{"url": "https://huggingface.co/spaces/openfree/Article-Generator", "is_liked": True},
|
| 31 |
]
|
| 32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
# URL์ ๋ง์ง๋ง ๋ถ๋ถ์ ์ ๋ชฉ์ผ๋ก ์ถ์ถ
|
| 34 |
def extract_title(url):
|
| 35 |
parts = url.split("/")
|
| 36 |
title = parts[-1] if parts else ""
|
| 37 |
return title.replace("_", " ").replace("-", " ")
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
@app.route('/')
|
| 40 |
def home():
|
| 41 |
return render_template('index.html')
|
|
|
|
| 47 |
if not token:
|
| 48 |
return jsonify({'success': False, 'message': 'ํ ํฐ์ ์
๋ ฅํด์ฃผ์ธ์.'})
|
| 49 |
|
| 50 |
+
# ๊ฐ๋จํ ํ ํฐ ๊ธธ์ด๋ง ๊ฒ์ฌ (์ค์ ๋ก๋ ๋ ๋ณต์กํ ๊ฒ์ฆ ํ์)
|
| 51 |
+
if len(token) < 5:
|
|
|
|
| 52 |
return jsonify({'success': False, 'message': '์ ํจํ์ง ์์ ํ ํฐ์
๋๋ค.'})
|
| 53 |
|
| 54 |
+
# ํ ํฐ์ ์ฒซ ๊ธ์๋ฅผ ์ฌ์ฉ์ ์ด๋ฆ์ผ๋ก ์ค์ (ํ
์คํธ์ฉ)
|
| 55 |
+
username = f"์ฌ์ฉ์_{token[:3]}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
# ์ธ์
์ ์ ์ฅ
|
|
|
|
| 58 |
session['username'] = username
|
| 59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
return jsonify({
|
| 61 |
'success': True,
|
| 62 |
'username': username
|
|
|
|
| 64 |
|
| 65 |
@app.route('/api/logout', methods=['POST'])
|
| 66 |
def logout():
|
|
|
|
| 67 |
session.pop('username', None)
|
|
|
|
| 68 |
return jsonify({'success': True})
|
| 69 |
|
| 70 |
@app.route('/api/urls', methods=['GET'])
|
| 71 |
def get_urls():
|
| 72 |
results = []
|
| 73 |
+
for url_item in HUGGINGFACE_URLS:
|
| 74 |
+
url = url_item["url"]
|
| 75 |
+
is_liked = url_item["is_liked"]
|
| 76 |
title = extract_title(url)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
|
| 78 |
results.append({
|
| 79 |
'url': url,
|
| 80 |
'title': title,
|
|
|
|
| 81 |
'is_liked': is_liked
|
| 82 |
})
|
| 83 |
|
|
|
|
| 94 |
if not url:
|
| 95 |
return jsonify({'success': False, 'message': 'URL์ด ํ์ํฉ๋๋ค.'})
|
| 96 |
|
| 97 |
+
# URL ๋ชฉ๋ก์์ ํด๋น URL ์ฐพ๊ธฐ
|
| 98 |
+
for url_item in HUGGINGFACE_URLS:
|
| 99 |
+
if url_item["url"] == url:
|
| 100 |
+
# ์ข์์ ์ํ ํ ๊ธ
|
| 101 |
+
url_item["is_liked"] = not url_item["is_liked"]
|
| 102 |
+
|
| 103 |
+
return jsonify({
|
| 104 |
+
'success': True,
|
| 105 |
+
'is_liked': url_item["is_liked"],
|
| 106 |
+
'message': '์ข์์๋ฅผ ์ถ๊ฐํ์ต๋๋ค.' if url_item["is_liked"] else '์ข์์๋ฅผ ์ทจ์ํ์ต๋๋ค.'
|
| 107 |
+
})
|
| 108 |
+
|
| 109 |
+
return jsonify({'success': False, 'message': 'ํด๋น URL์ ์ฐพ์ ์ ์์ต๋๋ค.'})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
@app.route('/api/session-status', methods=['GET'])
|
| 112 |
def session_status():
|
|
|
|
| 480 |
// ์ ํ๋ฆฌ์ผ์ด์
์ํ
|
| 481 |
const state = {
|
| 482 |
username: null,
|
|
|
|
| 483 |
allURLs: [],
|
| 484 |
isLoading: false,
|
| 485 |
viewMode: 'all' // 'all' ๋๋ 'liked'
|
|
|
|
| 515 |
// ์ข์์ ํต๊ณ ์
๋ฐ์ดํธ
|
| 516 |
function updateLikeStats() {
|
| 517 |
const totalCount = state.allURLs.length;
|
| 518 |
+
const likedCount = state.allURLs.filter(item => item.is_liked).length;
|
| 519 |
|
| 520 |
elements.totalUrlCount.textContent = totalCount;
|
| 521 |
elements.likedUrlCount.textContent = likedCount;
|
|
|
|
| 534 |
elements.loggedInSection.style.display = 'block';
|
| 535 |
elements.likeStatus.style.display = 'block';
|
| 536 |
|
|
|
|
|
|
|
|
|
|
| 537 |
// URL ๋ชฉ๋ก ๋ก๋
|
| 538 |
loadUrls();
|
| 539 |
}
|
|
|
|
| 542 |
}
|
| 543 |
}
|
| 544 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 545 |
// ๋ก๊ทธ์ธ ์ฒ๋ฆฌ
|
| 546 |
async function login(token) {
|
| 547 |
if (!token.trim()) {
|
|
|
|
| 572 |
|
| 573 |
showMessage(`${state.username}๋์ผ๋ก ๋ก๊ทธ์ธ๋์์ต๋๋ค.`);
|
| 574 |
|
|
|
|
|
|
|
|
|
|
| 575 |
// URL ๋ชฉ๋ก ๋ก๋
|
| 576 |
loadUrls();
|
| 577 |
} else {
|
|
|
|
| 598 |
|
| 599 |
if (data.success) {
|
| 600 |
state.username = null;
|
|
|
|
| 601 |
state.allURLs = [];
|
| 602 |
|
| 603 |
elements.currentUser.textContent = '๋ก๊ทธ์ธ๋์ง ์์';
|
|
|
|
| 630 |
// URL ๋ฐ ์ข์์ ์ํ ์ ์ฅ
|
| 631 |
state.allURLs = urls;
|
| 632 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 633 |
// ํํฐ๋ง ๋ฐ ๋ ๋๋ง
|
| 634 |
filterAndRenderCards();
|
| 635 |
|
|
|
|
| 649 |
|
| 650 |
// ํํฐ๋ง ์ ์ฉ
|
| 651 |
const filteredUrls = state.allURLs.filter(item => {
|
| 652 |
+
const { url, title, is_liked } = item;
|
| 653 |
|
| 654 |
// ์ข์์ ํํฐ๋ง (์ข์์๋ง ๋ณด๊ธฐ ๋ชจ๋)
|
| 655 |
+
if (state.viewMode === 'liked' && !is_liked) {
|
| 656 |
return false;
|
| 657 |
}
|
| 658 |
|
|
|
|
| 688 |
const data = await handleApiResponse(response);
|
| 689 |
|
| 690 |
if (data.success) {
|
| 691 |
+
// ์ํ ๊ฐ์ฒด์์ URL ์ฐพ๊ธฐ
|
| 692 |
+
const urlItem = state.allURLs.find(item => item.url === url);
|
| 693 |
+
if (urlItem) {
|
| 694 |
+
// ์ข์์ ์ํ ์
๋ฐ์ดํธ
|
| 695 |
+
urlItem.is_liked = data.is_liked;
|
| 696 |
+
|
| 697 |
+
// ์นด๋ UI ์
๋ฐ์ดํธ
|
| 698 |
+
if (data.is_liked) {
|
| 699 |
+
card.classList.add('liked');
|
| 700 |
+
const likeBtn = card.querySelector('.like-button');
|
| 701 |
+
if (likeBtn) likeBtn.classList.add('liked');
|
| 702 |
+
|
| 703 |
+
// ์ข์์ ๋ฐฐ์ง ์ถ๊ฐ
|
| 704 |
+
if (!card.querySelector('.like-badge')) {
|
| 705 |
+
const likeBadge = document.createElement('div');
|
| 706 |
+
likeBadge.className = 'like-badge';
|
| 707 |
+
likeBadge.textContent = '์ข์์';
|
| 708 |
+
card.appendChild(likeBadge);
|
| 709 |
+
}
|
| 710 |
+
} else {
|
| 711 |
+
card.classList.remove('liked');
|
| 712 |
+
const likeBtn = card.querySelector('.like-button');
|
| 713 |
+
if (likeBtn) likeBtn.classList.remove('liked');
|
| 714 |
+
|
| 715 |
+
// ์ข์์ ๋ฐฐ์ง ์ ๊ฑฐ
|
| 716 |
+
const likeBadge = card.querySelector('.like-badge');
|
| 717 |
+
if (likeBadge) card.removeChild(likeBadge);
|
| 718 |
+
}
|
| 719 |
}
|
| 720 |
|
| 721 |
showMessage(data.message);
|
|
|
|
| 752 |
}
|
| 753 |
|
| 754 |
urls.forEach(item => {
|
| 755 |
+
const { url, title, is_liked } = item;
|
|
|
|
| 756 |
|
| 757 |
// ์นด๋ ์์ฑ
|
| 758 |
const card = document.createElement('div');
|
| 759 |
+
card.className = `card ${is_liked ? 'liked' : ''}`;
|
| 760 |
|
| 761 |
// ์นด๋ ํค๋
|
| 762 |
const cardHeader = document.createElement('div');
|
|
|
|
| 772 |
|
| 773 |
// URL ๋งํฌ
|
| 774 |
const linkEl = document.createElement('a');
|
| 775 |
+
linkEl.href = url;
|
|
|
|
|
|
|
| 776 |
linkEl.textContent = url;
|
| 777 |
linkEl.target = '_blank';
|
| 778 |
card.appendChild(linkEl);
|
| 779 |
|
| 780 |
// ์ข์์ ๋ฒํผ
|
| 781 |
const likeBtn = document.createElement('button');
|
| 782 |
+
likeBtn.className = `like-button ${is_liked ? 'liked' : ''}`;
|
| 783 |
likeBtn.innerHTML = 'โฅ';
|
| 784 |
+
likeBtn.title = is_liked ? '์ข์์ ์ทจ์' : '์ข์์';
|
| 785 |
|
| 786 |
likeBtn.addEventListener('click', (e) => {
|
| 787 |
e.preventDefault();
|
|
|
|
| 791 |
card.appendChild(likeBtn);
|
| 792 |
|
| 793 |
// ์ข์์ ๋ฐฐ์ง (์ข์์ ์ํ์ผ ๋๋ง)
|
| 794 |
+
if (is_liked) {
|
| 795 |
const likeBadge = document.createElement('div');
|
| 796 |
likeBadge.className = 'like-badge';
|
| 797 |
likeBadge.textContent = '์ข์์';
|
|
|
|
| 815 |
filterAndRenderCards();
|
| 816 |
}
|
| 817 |
|
| 818 |
+
// ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ค์
|
| 819 |
elements.loginButton.addEventListener('click', () => {
|
| 820 |
login(elements.tokenInput.value);
|
| 821 |
});
|
|
|
|
| 848 |
''')
|
| 849 |
|
| 850 |
# ํ๊น
ํ์ด์ค ์คํ์ด์ค์์๋ 7860 ํฌํธ ์ฌ์ฉ
|
| 851 |
+
app.run(host='0.0.0.0', port=7860)
|