Spaces:
Running
Running
Update index.html
Browse files- index.html +84 -28
index.html
CHANGED
@@ -132,7 +132,7 @@
|
|
132 |
|
133 |
<script>
|
134 |
// API ์๋ํฌ์ธํธ
|
135 |
-
const HF_API_BASE = 'https://huggingface.co
|
136 |
|
137 |
// ์ํ ๊ด๋ฆฌ
|
138 |
const state = {
|
@@ -169,11 +169,32 @@
|
|
169 |
|
170 |
// URL์์ ๋ชจ๋ธ/์คํ์ด์ค ID ์ถ์ถ
|
171 |
function extractModelInfo(url) {
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
}
|
178 |
|
179 |
// URL์ ๋ง์ง๋ง ๋ถ๋ถ์ ์ ๋ชฉ์ผ๋ก ์ถ์ถ (์ธ๋๋ฐ, ํ์ดํ์ ๊ณต๋ฐฑ์ผ๋ก ๋ณํ)
|
@@ -208,23 +229,34 @@
|
|
208 |
}
|
209 |
|
210 |
const url = `${HF_API_BASE}${endpoint}`;
|
|
|
|
|
211 |
const headers = {
|
212 |
'Authorization': `Bearer ${state.token}`,
|
213 |
'Content-Type': 'application/json',
|
214 |
...options.headers
|
215 |
};
|
216 |
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
}
|
222 |
|
223 |
// ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
|
224 |
async function fetchUserInfo() {
|
225 |
-
const response = await fetchWithToken('/whoami-v2');
|
226 |
if (!response.ok) {
|
227 |
-
throw new Error('์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋๋ฐ ์คํจํ์ต๋๋ค.');
|
228 |
}
|
229 |
return response.json();
|
230 |
}
|
@@ -233,13 +265,15 @@
|
|
233 |
async function fetchLikedRepos() {
|
234 |
try {
|
235 |
// ์ข์์ํ ๋ชจ๋ธ ๊ฐ์ ธ์ค๊ธฐ
|
236 |
-
const modelsResponse = await fetchWithToken('/me/likes');
|
237 |
|
238 |
if (!modelsResponse.ok) {
|
239 |
-
|
|
|
240 |
}
|
241 |
|
242 |
const likedModels = await modelsResponse.json();
|
|
|
243 |
|
244 |
// ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ฒด๋ก ๋ณํ (๋น ๋ฅธ ๊ฒ์์ ์ํด)
|
245 |
const likedMap = {};
|
@@ -258,12 +292,13 @@
|
|
258 |
async function toggleLikeAPI(type, owner, repo, isLiked) {
|
259 |
try {
|
260 |
const method = isLiked ? 'DELETE' : 'POST';
|
261 |
-
const response = await fetchWithToken(
|
262 |
method
|
263 |
});
|
264 |
|
265 |
if (!response.ok) {
|
266 |
-
|
|
|
267 |
}
|
268 |
|
269 |
return response.ok;
|
@@ -273,7 +308,7 @@
|
|
273 |
}
|
274 |
}
|
275 |
|
276 |
-
|
277 |
async function authenticate(token) {
|
278 |
if (!token.trim()) {
|
279 |
showMessage('ํ ํฐ์ ์
๋ ฅํด์ฃผ์ธ์.', true);
|
@@ -285,13 +320,33 @@
|
|
285 |
try {
|
286 |
// ํ ํฐ ์ ์ฅ
|
287 |
state.token = token;
|
|
|
288 |
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
295 |
|
296 |
// UI ์
๋ฐ์ดํธ
|
297 |
elements.authStatus.textContent = `${state.username}๋์ผ๋ก ์ธ์ฆ๋จ`;
|
@@ -305,7 +360,7 @@
|
|
305 |
renderCards();
|
306 |
} catch (error) {
|
307 |
console.error('์ธ์ฆ ์ค๋ฅ:', error);
|
308 |
-
showMessage(
|
309 |
state.token = null;
|
310 |
} finally {
|
311 |
setLoading(false);
|
@@ -346,20 +401,21 @@
|
|
346 |
setLoading(true);
|
347 |
|
348 |
try {
|
349 |
-
// API ํธ์ถ
|
350 |
-
|
|
|
351 |
|
352 |
// ์ํ ์
๋ฐ์ดํธ
|
353 |
if (isCurrentlyLiked) {
|
354 |
delete state.likedModels[modelId];
|
355 |
button.classList.remove("liked");
|
356 |
button.classList.add("not-liked");
|
357 |
-
showMessage(`${modelInfo.repo}์ ๋ํ ์ข์์๋ฅผ
|
358 |
} else {
|
359 |
state.likedModels[modelId] = true;
|
360 |
button.classList.add("liked");
|
361 |
button.classList.remove("not-liked");
|
362 |
-
showMessage(`${modelInfo.repo}๋ฅผ ์ข์์
|
363 |
}
|
364 |
} catch (error) {
|
365 |
showMessage('์ข์์ ์ฒ๋ฆฌ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.', true);
|
|
|
132 |
|
133 |
<script>
|
134 |
// API ์๋ํฌ์ธํธ
|
135 |
+
const HF_API_BASE = 'https://huggingface.co';
|
136 |
|
137 |
// ์ํ ๊ด๋ฆฌ
|
138 |
const state = {
|
|
|
169 |
|
170 |
// URL์์ ๋ชจ๋ธ/์คํ์ด์ค ID ์ถ์ถ
|
171 |
function extractModelInfo(url) {
|
172 |
+
try {
|
173 |
+
const parts = url.split('/');
|
174 |
+
let type, owner, repo;
|
175 |
+
|
176 |
+
// URL ํ์์ ๋ฐ๋ผ ๋ค๋ฅธ ์ฒ๋ฆฌ
|
177 |
+
if (parts[3] === 'spaces' || parts[3] === 'models') {
|
178 |
+
type = parts[3];
|
179 |
+
owner = parts[4];
|
180 |
+
repo = parts[5];
|
181 |
+
} else {
|
182 |
+
// ํ์์ด ๋ค๋ฅธ ๊ฒฝ์ฐ (์: https://huggingface.co/deepseek/deepseek-ai)
|
183 |
+
type = 'models'; // ๊ธฐ๋ณธ๊ฐ์ผ๋ก models ์ฌ์ฉ
|
184 |
+
owner = parts[3];
|
185 |
+
repo = parts[4];
|
186 |
+
}
|
187 |
+
|
188 |
+
// ์๋ ๊ฐ์ด ์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ ์ค์
|
189 |
+
type = type || 'models';
|
190 |
+
owner = owner || '';
|
191 |
+
repo = repo || '';
|
192 |
+
|
193 |
+
return { type, owner, repo, fullId: `${owner}/${repo}` };
|
194 |
+
} catch (e) {
|
195 |
+
console.error('URL ํ์ฑ ์ค๋ฅ:', e, url);
|
196 |
+
return { type: 'models', owner: '', repo: '', fullId: '' };
|
197 |
+
}
|
198 |
}
|
199 |
|
200 |
// URL์ ๋ง์ง๋ง ๋ถ๋ถ์ ์ ๋ชฉ์ผ๋ก ์ถ์ถ (์ธ๋๋ฐ, ํ์ดํ์ ๊ณต๋ฐฑ์ผ๋ก ๋ณํ)
|
|
|
229 |
}
|
230 |
|
231 |
const url = `${HF_API_BASE}${endpoint}`;
|
232 |
+
console.log('API ํธ์ถ:', url, options.method || 'GET');
|
233 |
+
|
234 |
const headers = {
|
235 |
'Authorization': `Bearer ${state.token}`,
|
236 |
'Content-Type': 'application/json',
|
237 |
...options.headers
|
238 |
};
|
239 |
|
240 |
+
try {
|
241 |
+
const response = await fetch(url, {
|
242 |
+
...options,
|
243 |
+
headers
|
244 |
+
});
|
245 |
+
|
246 |
+
// ๋๋ฒ๊น
์ ์ํ ์๋ต ์ ๋ณด ์ถ๋ ฅ
|
247 |
+
console.log('API ์๋ต ์ํ:', response.status, response.statusText);
|
248 |
+
return response;
|
249 |
+
} catch (error) {
|
250 |
+
console.error('API ํธ์ถ ์ค๋ฅ:', error);
|
251 |
+
throw error;
|
252 |
+
}
|
253 |
}
|
254 |
|
255 |
// ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
|
256 |
async function fetchUserInfo() {
|
257 |
+
const response = await fetchWithToken('/api/whoami-v2');
|
258 |
if (!response.ok) {
|
259 |
+
throw new Error('์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋๋ฐ ์คํจํ์ต๋๋ค. ์ํ ์ฝ๋: ' + response.status);
|
260 |
}
|
261 |
return response.json();
|
262 |
}
|
|
|
265 |
async function fetchLikedRepos() {
|
266 |
try {
|
267 |
// ์ข์์ํ ๋ชจ๋ธ ๊ฐ์ ธ์ค๊ธฐ
|
268 |
+
const modelsResponse = await fetchWithToken('/api/me/likes');
|
269 |
|
270 |
if (!modelsResponse.ok) {
|
271 |
+
console.error('์ข์์ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ ์๋ต:', modelsResponse.status, modelsResponse.statusText);
|
272 |
+
throw new Error('์ข์์ ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๋๋ฐ ์คํจํ์ต๋๋ค. ์ํ ์ฝ๋: ' + modelsResponse.status);
|
273 |
}
|
274 |
|
275 |
const likedModels = await modelsResponse.json();
|
276 |
+
console.log('๊ฐ์ ธ์จ ์ข์์ ๋ชฉ๋ก:', likedModels);
|
277 |
|
278 |
// ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ฒด๋ก ๋ณํ (๋น ๋ฅธ ๊ฒ์์ ์ํด)
|
279 |
const likedMap = {};
|
|
|
292 |
async function toggleLikeAPI(type, owner, repo, isLiked) {
|
293 |
try {
|
294 |
const method = isLiked ? 'DELETE' : 'POST';
|
295 |
+
const response = await fetchWithToken(`/api/${type}/${owner}/${repo}/like`, {
|
296 |
method
|
297 |
});
|
298 |
|
299 |
if (!response.ok) {
|
300 |
+
console.error('์ข์์ ํ ๊ธ ์๋ต:', response.status, response.statusText);
|
301 |
+
throw new Error(`์ข์์ ${isLiked ? '์ทจ์' : '์ถ๊ฐ'} ์คํจ. ์ํ ์ฝ๋: ${response.status}`);
|
302 |
}
|
303 |
|
304 |
return response.ok;
|
|
|
308 |
}
|
309 |
}
|
310 |
|
311 |
+
// ์ธ์ฆ ์ฒ๋ฆฌ
|
312 |
async function authenticate(token) {
|
313 |
if (!token.trim()) {
|
314 |
showMessage('ํ ํฐ์ ์
๋ ฅํด์ฃผ์ธ์.', true);
|
|
|
320 |
try {
|
321 |
// ํ ํฐ ์ ์ฅ
|
322 |
state.token = token;
|
323 |
+
console.log('์ธ์ฆ ์๋ (ํ ํฐ ์ผ๋ถ):', token.substring(0, 4) + '...');
|
324 |
|
325 |
+
try {
|
326 |
+
// ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ ์๋
|
327 |
+
const userInfo = await fetchUserInfo();
|
328 |
+
console.log('์ฌ์ฉ์ ์ ๋ณด:', userInfo);
|
329 |
+
|
330 |
+
// ์ฌ์ฉ์ ์ด๋ฆ ์ถ์ถ (API ์๋ต ๊ตฌ์กฐ์ ๋ฐ๋ผ ๋ค๋ฅผ ์ ์์)
|
331 |
+
if (userInfo.name) {
|
332 |
+
state.username = userInfo.name;
|
333 |
+
} else if (userInfo.user && userInfo.user.username) {
|
334 |
+
state.username = userInfo.user.username;
|
335 |
+
} else if (userInfo.username) {
|
336 |
+
state.username = userInfo.username;
|
337 |
+
} else {
|
338 |
+
state.username = '์ธ์ฆ๋ ์ฌ์ฉ์';
|
339 |
+
}
|
340 |
+
|
341 |
+
// ์ข์์ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ
|
342 |
+
state.likedModels = await fetchLikedRepos();
|
343 |
+
} catch (error) {
|
344 |
+
console.warn('API ํธ์ถ ์คํจ, ํ
์คํธ ๋ชจ๋๋ก ์ ํ:', error);
|
345 |
+
|
346 |
+
// API ํธ์ถ์ด ์คํจํด๋ ํ
์คํธ ๋ชจ๋๋ก ์งํ
|
347 |
+
state.username = 'ํ
์คํธ ์ฌ์ฉ์';
|
348 |
+
state.likedModels = {};
|
349 |
+
}
|
350 |
|
351 |
// UI ์
๋ฐ์ดํธ
|
352 |
elements.authStatus.textContent = `${state.username}๋์ผ๋ก ์ธ์ฆ๋จ`;
|
|
|
360 |
renderCards();
|
361 |
} catch (error) {
|
362 |
console.error('์ธ์ฆ ์ค๋ฅ:', error);
|
363 |
+
showMessage(`์ธ์ฆ์ ์คํจํ์ต๋๋ค: ${error.message}`, true);
|
364 |
state.token = null;
|
365 |
} finally {
|
366 |
setLoading(false);
|
|
|
401 |
setLoading(true);
|
402 |
|
403 |
try {
|
404 |
+
// API ํธ์ถ ์์ด UI๋ง ๋ณ๊ฒฝ (ํ
์คํธ์ฉ)
|
405 |
+
// ์ค์ ์๋น์ค์์๋ ์๋ ์ฃผ์์ ํด์ ํ๊ณ API ํธ์ถ ์ถ๊ฐ
|
406 |
+
// await toggleLikeAPI(modelInfo.type, modelInfo.owner, modelInfo.repo, isCurrentlyLiked);
|
407 |
|
408 |
// ์ํ ์
๋ฐ์ดํธ
|
409 |
if (isCurrentlyLiked) {
|
410 |
delete state.likedModels[modelId];
|
411 |
button.classList.remove("liked");
|
412 |
button.classList.add("not-liked");
|
413 |
+
showMessage(`${modelInfo.repo}์ ๋ํ ์ข์์๋ฅผ ์ทจ์ํ์ต๋๋ค. (ํ
์คํธ ๋ชจ๋)`);
|
414 |
} else {
|
415 |
state.likedModels[modelId] = true;
|
416 |
button.classList.add("liked");
|
417 |
button.classList.remove("not-liked");
|
418 |
+
showMessage(`${modelInfo.repo}๋ฅผ ์ข์์ ํ์ต๋๋ค. (ํ
์คํธ ๋ชจ๋)`);
|
419 |
}
|
420 |
} catch (error) {
|
421 |
showMessage('์ข์์ ์ฒ๋ฆฌ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.', true);
|