Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- README.md +5 -0
- code/server/routes.py +79 -0
- index.html +200 -9
README.md
CHANGED
|
@@ -8,6 +8,11 @@ sdk_version: 6.14.0
|
|
| 8 |
python_version: '3.11'
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
## SoniCoder
|
|
|
|
| 8 |
python_version: '3.11'
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
| 11 |
+
hf_oauth: true
|
| 12 |
+
hf_oauth_scopes:
|
| 13 |
+
- read-repos
|
| 14 |
+
- write-repos
|
| 15 |
+
- manage-repos
|
| 16 |
---
|
| 17 |
|
| 18 |
## SoniCoder
|
code/server/routes.py
CHANGED
|
@@ -10,6 +10,7 @@ Defines all HTTP and API endpoints:
|
|
| 10 |
- API push_hf β push to HuggingFace Hub
|
| 11 |
- API switch_model β switch between loaded models
|
| 12 |
- API upload_image β upload image for VLM inference
|
|
|
|
| 13 |
"""
|
| 14 |
|
| 15 |
from __future__ import annotations
|
|
@@ -470,6 +471,84 @@ def handle_chat(
|
|
| 470 |
})
|
| 471 |
|
| 472 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 473 |
@app.api(name="push_hf", concurrency_limit=1)
|
| 474 |
def handle_push_hf(
|
| 475 |
exec_context_json: str,
|
|
|
|
| 10 |
- API push_hf β push to HuggingFace Hub
|
| 11 |
- API switch_model β switch between loaded models
|
| 12 |
- API upload_image β upload image for VLM inference
|
| 13 |
+
- API hf_auth β get HF OAuth profile & organizations
|
| 14 |
"""
|
| 15 |
|
| 16 |
from __future__ import annotations
|
|
|
|
| 471 |
})
|
| 472 |
|
| 473 |
|
| 474 |
+
@app.api(name="hf_auth", concurrency_limit=4)
|
| 475 |
+
def handle_hf_auth(
|
| 476 |
+
oauth_token: str = "",
|
| 477 |
+
) -> str:
|
| 478 |
+
"""Get HuggingFace OAuth profile and list of organizations.
|
| 479 |
+
|
| 480 |
+
If oauth_token is provided (from Gradio OAuth), uses it to fetch user info.
|
| 481 |
+
Otherwise, returns empty auth info.
|
| 482 |
+
"""
|
| 483 |
+
try:
|
| 484 |
+
import gradio as gr
|
| 485 |
+
from huggingface_hub import whoami
|
| 486 |
+
|
| 487 |
+
token = oauth_token.strip() if oauth_token else ""
|
| 488 |
+
|
| 489 |
+
if not token:
|
| 490 |
+
yield json.dumps({
|
| 491 |
+
"authenticated": False,
|
| 492 |
+
"username": "",
|
| 493 |
+
"name": "",
|
| 494 |
+
"picture": "",
|
| 495 |
+
"organizations": [],
|
| 496 |
+
"message": "Not signed in. Click Sign In to authenticate with HuggingFace.",
|
| 497 |
+
})
|
| 498 |
+
return
|
| 499 |
+
|
| 500 |
+
# Get user info using the OAuth token
|
| 501 |
+
user_info = whoami(token=token)
|
| 502 |
+
username = user_info.get("name", "")
|
| 503 |
+
fullname = user_info.get("fullname", username)
|
| 504 |
+
|
| 505 |
+
# Get avatar
|
| 506 |
+
avatar_url = ""
|
| 507 |
+
avatar_info = user_info.get("avatarUrl", "")
|
| 508 |
+
if avatar_info:
|
| 509 |
+
avatar_url = avatar_info
|
| 510 |
+
|
| 511 |
+
# Get organizations
|
| 512 |
+
orgs = []
|
| 513 |
+
for org in user_info.get("orgs", []):
|
| 514 |
+
orgs.append({
|
| 515 |
+
"name": org.get("name", ""),
|
| 516 |
+
"avatar": org.get("avatarUrl", ""),
|
| 517 |
+
})
|
| 518 |
+
|
| 519 |
+
# Also check orgRoles for role info
|
| 520 |
+
org_roles = user_info.get("orgRoles", [])
|
| 521 |
+
for role_info in org_roles:
|
| 522 |
+
org_name = role_info.get("org", "")
|
| 523 |
+
role = role_info.get("role", "member")
|
| 524 |
+
# Add role info to existing org if found
|
| 525 |
+
for org in orgs:
|
| 526 |
+
if org["name"] == org_name:
|
| 527 |
+
org["role"] = role
|
| 528 |
+
break
|
| 529 |
+
|
| 530 |
+
yield json.dumps({
|
| 531 |
+
"authenticated": True,
|
| 532 |
+
"username": username,
|
| 533 |
+
"name": fullname,
|
| 534 |
+
"picture": avatar_url,
|
| 535 |
+
"organizations": orgs,
|
| 536 |
+
"token": token,
|
| 537 |
+
"message": f"Signed in as {username}",
|
| 538 |
+
})
|
| 539 |
+
|
| 540 |
+
except Exception as exc:
|
| 541 |
+
logger.exception("HF auth check failed")
|
| 542 |
+
yield json.dumps({
|
| 543 |
+
"authenticated": False,
|
| 544 |
+
"username": "",
|
| 545 |
+
"name": "",
|
| 546 |
+
"picture": "",
|
| 547 |
+
"organizations": [],
|
| 548 |
+
"message": f"Auth check failed: {str(exc)}",
|
| 549 |
+
})
|
| 550 |
+
|
| 551 |
+
|
| 552 |
@app.api(name="push_hf", concurrency_limit=1)
|
| 553 |
def handle_push_hf(
|
| 554 |
exec_context_json: str,
|
index.html
CHANGED
|
@@ -943,6 +943,36 @@ body.hide-thinking .think-block { display: none; }
|
|
| 943 |
cursor: not-allowed;
|
| 944 |
}
|
| 945 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 946 |
.deploy-status {
|
| 947 |
margin-top: 10px;
|
| 948 |
padding: 8px 12px;
|
|
@@ -1189,16 +1219,42 @@ body.hide-thinking .think-block { display: none; }
|
|
| 1189 |
<div class="tab-pane" id="pane-deploy">
|
| 1190 |
<div class="deploy-section">
|
| 1191 |
<div class="deploy-title">🚀 Deploy to HuggingFace</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1192 |
<div class="deploy-field">
|
| 1193 |
-
<label for="hf-
|
| 1194 |
-
<
|
| 1195 |
-
|
|
|
|
|
|
|
| 1196 |
</div>
|
|
|
|
| 1197 |
<div class="deploy-field">
|
| 1198 |
-
<label for="hf-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1199 |
<input type="password" id="hf-token" placeholder="hf_xxxxxxxxxxxxxxxxxxxxx" autocomplete="off">
|
| 1200 |
-
<div class="deploy-hint">
|
| 1201 |
</div>
|
|
|
|
| 1202 |
<div class="deploy-field">
|
| 1203 |
<label for="hf-space-sdk">Space SDK</label>
|
| 1204 |
<select id="hf-space-sdk">
|
|
@@ -1321,6 +1377,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
| 1321 |
|
| 1322 |
// Poll model status
|
| 1323 |
pollModelStatus();
|
|
|
|
|
|
|
|
|
|
| 1324 |
});
|
| 1325 |
|
| 1326 |
function autoResize() {
|
|
@@ -2435,23 +2494,155 @@ function toggleSearchPanel(badge) {
|
|
| 2435 |
}
|
| 2436 |
|
| 2437 |
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2438 |
-
// HUGGINGFACE PUSH
|
| 2439 |
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2440 |
async function pushToHuggingFace() {
|
|
|
|
|
|
|
| 2441 |
const repoName = document.getElementById('hf-repo-name').value.trim();
|
| 2442 |
const hfToken = document.getElementById('hf-token').value.trim();
|
| 2443 |
const spaceSdk = document.getElementById('hf-space-sdk').value;
|
| 2444 |
const statusEl = document.getElementById('deploy-status');
|
| 2445 |
|
| 2446 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2447 |
statusEl.className = 'deploy-status error';
|
| 2448 |
statusEl.textContent = 'Please enter a repository name.';
|
| 2449 |
statusEl.style.display = 'block';
|
| 2450 |
return;
|
| 2451 |
}
|
|
|
|
| 2452 |
if (!hfToken) {
|
| 2453 |
statusEl.className = 'deploy-status error';
|
| 2454 |
-
statusEl.textContent = 'Please
|
| 2455 |
statusEl.style.display = 'block';
|
| 2456 |
return;
|
| 2457 |
}
|
|
@@ -2477,7 +2668,7 @@ async function pushToHuggingFace() {
|
|
| 2477 |
method: 'POST',
|
| 2478 |
headers: { 'Content-Type': 'application/json' },
|
| 2479 |
body: JSON.stringify({
|
| 2480 |
-
data: [execContextJSON,
|
| 2481 |
})
|
| 2482 |
});
|
| 2483 |
|
|
|
|
| 943 |
cursor: not-allowed;
|
| 944 |
}
|
| 945 |
|
| 946 |
+
#btn-hf-login {
|
| 947 |
+
background: linear-gradient(135deg, #FFD21E, #FF9D00);
|
| 948 |
+
border: none;
|
| 949 |
+
color: #1a1a1a;
|
| 950 |
+
font-family: var(--font-mono);
|
| 951 |
+
font-size: 12px;
|
| 952 |
+
font-weight: 600;
|
| 953 |
+
padding: 8px 16px;
|
| 954 |
+
border-radius: 20px;
|
| 955 |
+
cursor: pointer;
|
| 956 |
+
transition: all var(--transition);
|
| 957 |
+
letter-spacing: 0.5px;
|
| 958 |
+
}
|
| 959 |
+
#btn-hf-login:hover {
|
| 960 |
+
box-shadow: 0 0 12px rgba(255,210,30,0.5);
|
| 961 |
+
transform: translateY(-1px);
|
| 962 |
+
}
|
| 963 |
+
|
| 964 |
+
#hf-owner {
|
| 965 |
+
width: 100%;
|
| 966 |
+
background: var(--bg-code);
|
| 967 |
+
color: var(--gray-light);
|
| 968 |
+
border: 1px solid var(--border);
|
| 969 |
+
font-family: var(--font-mono);
|
| 970 |
+
font-size: 12px;
|
| 971 |
+
padding: 6px 10px;
|
| 972 |
+
border-radius: var(--radius);
|
| 973 |
+
cursor: pointer;
|
| 974 |
+
}
|
| 975 |
+
|
| 976 |
.deploy-status {
|
| 977 |
margin-top: 10px;
|
| 978 |
padding: 8px 12px;
|
|
|
|
| 1219 |
<div class="tab-pane" id="pane-deploy">
|
| 1220 |
<div class="deploy-section">
|
| 1221 |
<div class="deploy-title">🚀 Deploy to HuggingFace</div>
|
| 1222 |
+
|
| 1223 |
+
<!-- OAuth Login Section -->
|
| 1224 |
+
<div class="deploy-field" id="hf-auth-section">
|
| 1225 |
+
<label>Sign In</label>
|
| 1226 |
+
<div id="hf-auth-container">
|
| 1227 |
+
<button id="btn-hf-login" onclick="loginWithHF()">🤝 Sign in with HuggingFace</button>
|
| 1228 |
+
<div id="hf-user-info" style="display:none;">
|
| 1229 |
+
<img id="hf-user-avatar" src="" alt="" style="width:24px;height:24px;border-radius:50%;vertical-align:middle;margin-right:6px;">
|
| 1230 |
+
<span id="hf-user-name" style="color:var(--green);font-weight:600;"></span>
|
| 1231 |
+
<button id="btn-hf-logout" onclick="logoutHF()" style="margin-left:8px;font-size:10px;color:var(--red);background:none;border:none;cursor:pointer;">Sign out</button>
|
| 1232 |
+
</div>
|
| 1233 |
+
</div>
|
| 1234 |
+
<div class="deploy-hint" id="hf-auth-hint">Sign in with OAuth β no token paste needed</div>
|
| 1235 |
+
</div>
|
| 1236 |
+
|
| 1237 |
+
<!-- Push to: User or Org selector -->
|
| 1238 |
<div class="deploy-field">
|
| 1239 |
+
<label for="hf-owner">Push to</label>
|
| 1240 |
+
<select id="hf-owner">
|
| 1241 |
+
<option value="">Sign in to see options</option>
|
| 1242 |
+
</select>
|
| 1243 |
+
<div class="deploy-hint">Select your account or an organization</div>
|
| 1244 |
</div>
|
| 1245 |
+
|
| 1246 |
<div class="deploy-field">
|
| 1247 |
+
<label for="hf-repo-name">Repository Name</label>
|
| 1248 |
+
<input type="text" id="hf-repo-name" placeholder="my-app" autocomplete="off">
|
| 1249 |
+
<div class="deploy-hint">The repo will be created at owner/repo-name</div>
|
| 1250 |
+
</div>
|
| 1251 |
+
|
| 1252 |
+
<div class="deploy-field" id="hf-manual-token-section">
|
| 1253 |
+
<label for="hf-token">HuggingFace Token <span style="font-weight:400;color:var(--gray-dim);">(manual fallback)</span></label>
|
| 1254 |
<input type="password" id="hf-token" placeholder="hf_xxxxxxxxxxxxxxxxxxxxx" autocomplete="off">
|
| 1255 |
+
<div class="deploy-hint">Only needed if OAuth is unavailable. <a href="https://huggingface.co/settings/tokens" target="_blank">Get token</a></div>
|
| 1256 |
</div>
|
| 1257 |
+
|
| 1258 |
<div class="deploy-field">
|
| 1259 |
<label for="hf-space-sdk">Space SDK</label>
|
| 1260 |
<select id="hf-space-sdk">
|
|
|
|
| 1377 |
|
| 1378 |
// Poll model status
|
| 1379 |
pollModelStatus();
|
| 1380 |
+
|
| 1381 |
+
// Check for HuggingFace OAuth session
|
| 1382 |
+
checkGradioOAuth();
|
| 1383 |
});
|
| 1384 |
|
| 1385 |
function autoResize() {
|
|
|
|
| 2494 |
}
|
| 2495 |
|
| 2496 |
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2497 |
+
// HUGGINGFACE OAUTH + PUSH
|
| 2498 |
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2499 |
+
|
| 2500 |
+
// OAuth state
|
| 2501 |
+
state.hfAuth = {
|
| 2502 |
+
authenticated: false,
|
| 2503 |
+
token: '',
|
| 2504 |
+
username: '',
|
| 2505 |
+
name: '',
|
| 2506 |
+
picture: '',
|
| 2507 |
+
organizations: [],
|
| 2508 |
+
};
|
| 2509 |
+
|
| 2510 |
+
async function loginWithHF() {
|
| 2511 |
+
// On HuggingFace Spaces, Gradio handles OAuth via /login/huggingface
|
| 2512 |
+
// We redirect to the Gradio OAuth endpoint
|
| 2513 |
+
const currentUrl = window.location.href;
|
| 2514 |
+
const loginUrl = `/login/huggingface?callback_url=${encodeURIComponent(currentUrl)}`;
|
| 2515 |
+
window.location.href = loginUrl;
|
| 2516 |
+
}
|
| 2517 |
+
|
| 2518 |
+
function logoutHF() {
|
| 2519 |
+
state.hfAuth = {
|
| 2520 |
+
authenticated: false,
|
| 2521 |
+
token: '',
|
| 2522 |
+
username: '',
|
| 2523 |
+
name: '',
|
| 2524 |
+
picture: '',
|
| 2525 |
+
organizations: [],
|
| 2526 |
+
};
|
| 2527 |
+
// Update UI
|
| 2528 |
+
document.getElementById('btn-hf-login').style.display = '';
|
| 2529 |
+
document.getElementById('hf-user-info').style.display = 'none';
|
| 2530 |
+
document.getElementById('hf-manual-token-section').style.display = '';
|
| 2531 |
+
document.getElementById('hf-auth-hint').textContent = 'Sign in with OAuth β no token paste needed';
|
| 2532 |
+
// Reset owner dropdown
|
| 2533 |
+
const ownerSelect = document.getElementById('hf-owner');
|
| 2534 |
+
ownerSelect.innerHTML = '<option value="">Sign in to see options</option>';
|
| 2535 |
+
// Check for Gradio OAuth token in session
|
| 2536 |
+
checkGradioOAuth();
|
| 2537 |
+
}
|
| 2538 |
+
|
| 2539 |
+
async function checkGradioOAuth() {
|
| 2540 |
+
// Try to get the OAuth token from Gradio's session
|
| 2541 |
+
// Gradio stores the token in cookies/session after OAuth login
|
| 2542 |
+
try {
|
| 2543 |
+
// Check if we have a Gradio session with OAuth token
|
| 2544 |
+
const resp = await fetch('/gradio_api/call/hf_auth', {
|
| 2545 |
+
method: 'POST',
|
| 2546 |
+
headers: { 'Content-Type': 'application/json' },
|
| 2547 |
+
body: JSON.stringify({ data: [''] })
|
| 2548 |
+
});
|
| 2549 |
+
|
| 2550 |
+
if (!resp.ok) return;
|
| 2551 |
+
|
| 2552 |
+
const { event_id } = await resp.json();
|
| 2553 |
+
const eventSource = new EventSource(`/gradio_api/call/hf_auth/${event_id}`);
|
| 2554 |
+
|
| 2555 |
+
eventSource.addEventListener('complete', (e) => {
|
| 2556 |
+
try {
|
| 2557 |
+
const dataArray = JSON.parse(e.data);
|
| 2558 |
+
const result = JSON.parse(dataArray[0]);
|
| 2559 |
+
if (result.authenticated) {
|
| 2560 |
+
handleAuthResult(result);
|
| 2561 |
+
}
|
| 2562 |
+
} catch (err) { /* not authenticated */ }
|
| 2563 |
+
eventSource.close();
|
| 2564 |
+
});
|
| 2565 |
+
|
| 2566 |
+
eventSource.addEventListener('error', () => { eventSource.close(); });
|
| 2567 |
+
} catch (err) {
|
| 2568 |
+
// OAuth not available β show manual token input
|
| 2569 |
+
}
|
| 2570 |
+
}
|
| 2571 |
+
|
| 2572 |
+
function handleAuthResult(result) {
|
| 2573 |
+
state.hfAuth = {
|
| 2574 |
+
authenticated: result.authenticated,
|
| 2575 |
+
token: result.token || '',
|
| 2576 |
+
username: result.username || '',
|
| 2577 |
+
name: result.name || '',
|
| 2578 |
+
picture: result.picture || '',
|
| 2579 |
+
organizations: result.organizations || [],
|
| 2580 |
+
};
|
| 2581 |
+
|
| 2582 |
+
if (result.authenticated) {
|
| 2583 |
+
// Update UI β show user info
|
| 2584 |
+
document.getElementById('btn-hf-login').style.display = 'none';
|
| 2585 |
+
document.getElementById('hf-user-info').style.display = '';
|
| 2586 |
+
document.getElementById('hf-user-name').textContent = result.name || result.username;
|
| 2587 |
+
if (result.picture) {
|
| 2588 |
+
document.getElementById('hf-user-avatar').src = result.picture;
|
| 2589 |
+
document.getElementById('hf-user-avatar').style.display = '';
|
| 2590 |
+
} else {
|
| 2591 |
+
document.getElementById('hf-user-avatar').style.display = 'none';
|
| 2592 |
+
}
|
| 2593 |
+
document.getElementById('hf-auth-hint').textContent = `Signed in as ${result.username}`;
|
| 2594 |
+
document.getElementById('hf-manual-token-section').style.display = 'none';
|
| 2595 |
+
|
| 2596 |
+
// Populate owner dropdown
|
| 2597 |
+
const ownerSelect = document.getElementById('hf-owner');
|
| 2598 |
+
ownerSelect.innerHTML = '';
|
| 2599 |
+
|
| 2600 |
+
// Add user as first option
|
| 2601 |
+
const userOpt = document.createElement('option');
|
| 2602 |
+
userOpt.value = result.username;
|
| 2603 |
+
userOpt.textContent = `${result.username} (you)`;
|
| 2604 |
+
ownerSelect.appendChild(userOpt);
|
| 2605 |
+
|
| 2606 |
+
// Add organizations
|
| 2607 |
+
if (result.organizations && result.organizations.length > 0) {
|
| 2608 |
+
result.organizations.forEach(org => {
|
| 2609 |
+
const opt = document.createElement('option');
|
| 2610 |
+
opt.value = org.name;
|
| 2611 |
+
const roleSuffix = org.role ? ` (${org.role})` : '';
|
| 2612 |
+
opt.textContent = `${org.name}${roleSuffix}`;
|
| 2613 |
+
ownerSelect.appendChild(opt);
|
| 2614 |
+
});
|
| 2615 |
+
}
|
| 2616 |
+
|
| 2617 |
+
// Auto-fill token in hidden field for push
|
| 2618 |
+
document.getElementById('hf-token').value = result.token;
|
| 2619 |
+
}
|
| 2620 |
+
}
|
| 2621 |
+
|
| 2622 |
async function pushToHuggingFace() {
|
| 2623 |
+
const ownerSelect = document.getElementById('hf-owner');
|
| 2624 |
+
const owner = ownerSelect.value;
|
| 2625 |
const repoName = document.getElementById('hf-repo-name').value.trim();
|
| 2626 |
const hfToken = document.getElementById('hf-token').value.trim();
|
| 2627 |
const spaceSdk = document.getElementById('hf-space-sdk').value;
|
| 2628 |
const statusEl = document.getElementById('deploy-status');
|
| 2629 |
|
| 2630 |
+
// Build full repo name
|
| 2631 |
+
let fullRepoName = repoName;
|
| 2632 |
+
if (owner && repoName && !repoName.includes('/')) {
|
| 2633 |
+
fullRepoName = `${owner}/${repoName}`;
|
| 2634 |
+
}
|
| 2635 |
+
|
| 2636 |
+
if (!fullRepoName) {
|
| 2637 |
statusEl.className = 'deploy-status error';
|
| 2638 |
statusEl.textContent = 'Please enter a repository name.';
|
| 2639 |
statusEl.style.display = 'block';
|
| 2640 |
return;
|
| 2641 |
}
|
| 2642 |
+
|
| 2643 |
if (!hfToken) {
|
| 2644 |
statusEl.className = 'deploy-status error';
|
| 2645 |
+
statusEl.textContent = 'Please sign in with HuggingFace or enter a token.';
|
| 2646 |
statusEl.style.display = 'block';
|
| 2647 |
return;
|
| 2648 |
}
|
|
|
|
| 2668 |
method: 'POST',
|
| 2669 |
headers: { 'Content-Type': 'application/json' },
|
| 2670 |
body: JSON.stringify({
|
| 2671 |
+
data: [execContextJSON, fullRepoName, hfToken, spaceSdk, 'true']
|
| 2672 |
})
|
| 2673 |
});
|
| 2674 |
|