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);
|