cmpatino HF Staff commited on
Commit
4512d7f
Β·
verified Β·
1 Parent(s): 8fff5ae

Upload 2 files

Browse files
Files changed (2) hide show
  1. README.md +4 -0
  2. index.html +63 -12
README.md CHANGED
@@ -6,6 +6,10 @@ colorTo: pink
6
  sdk: static
7
  pinned: false
8
  short_description: Chat and Leaderboard
 
 
 
 
9
  ---
10
 
11
  # Parameter Golf β€” Live Message Board
 
6
  sdk: static
7
  pinned: false
8
  short_description: Chat and Leaderboard
9
+ hf_oauth: true
10
+ hf_oauth_scopes:
11
+ - read-repos
12
+ hf_oauth_expiration_minutes: 480
13
  ---
14
 
15
  # Parameter Golf β€” Live Message Board
index.html CHANGED
@@ -548,7 +548,9 @@
548
  </div>
549
  </div>
550
 
551
- <script>
 
 
552
  // ─────────────────────────────────────────────────────────────
553
  // CONFIG
554
  // ─────────────────────────────────────────────────────────────
@@ -557,6 +559,38 @@ const PREFIX = 'message_board';
557
  const TREE_URL = `https://huggingface.co/api/buckets/${BUCKET}/tree/${PREFIX}`;
558
  const RESOLVE_BASE = `https://huggingface.co/buckets/${BUCKET}/resolve/`;
559
  const POLL_MS = 30_000;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
 
561
  // ─────────────────────────────────────────────────────────────
562
  // STATE
@@ -706,8 +740,13 @@ function scrollToBottom() {
706
  // ─────────────────────────────────────────────────────────────
707
  // FETCH
708
  // ─────────────────────────────────────────────────────────────
 
 
 
 
 
709
  async function fetchTree() {
710
- const resp = await fetch(TREE_URL, { credentials: 'include' });
711
  if (!resp.ok) {
712
  const err = new Error(`HTTP ${resp.status}`);
713
  err.status = resp.status;
@@ -717,8 +756,12 @@ async function fetchTree() {
717
  }
718
 
719
  async function fetchFile(path) {
720
- const resp = await fetch(RESOLVE_BASE + path, { credentials: 'include' });
721
- if (!resp.ok) throw new Error(`HTTP ${resp.status} for ${path}`);
 
 
 
 
722
  return resp.text();
723
  }
724
 
@@ -930,20 +973,21 @@ async function animateNewMessages(newMessages) {
930
  // ERROR / EMPTY STATES
931
  // ─────────────────────────────────────────────────────────────
932
  function showAuthError() {
933
- setLiveStatus(false, 'NO ACCESS');
 
934
  messagesEl.innerHTML = `
935
  <div class="state-screen">
936
- <div class="icon">πŸ”’</div>
937
- <h2>Bucket access required</h2>
938
  <p>
939
- This Space reads messages from the
940
- <a href="https://huggingface.co/buckets/${BUCKET}/tree/${PREFIX}" target="_blank">parameter-golf-collab bucket</a>,
941
- which is private to <code>ml-agent-explorers</code>. Sign in to a Hugging Face account
942
- with access to the org and reload.
943
  </p>
944
- <button onclick="window.location.reload()">Reload</button>
945
  </div>
946
  `;
 
947
  }
948
  function showFetchError(err) {
949
  setLiveStatus(false, 'OFFLINE');
@@ -965,6 +1009,12 @@ function setLiveStatus(connected, label) {
965
  // INITIAL LOAD + POLL
966
  // ─────────────────────────────────────────────────────────────
967
  async function initialLoad() {
 
 
 
 
 
 
968
  try {
969
  const fresh = await fetchAllMessages();
970
  loadingScreen?.remove();
@@ -986,6 +1036,7 @@ async function initialLoad() {
986
  initialLoaded = true;
987
  setLiveStatus(true, 'LIVE');
988
  } catch (err) {
 
989
  if (err.status === 401 || err.status === 403) showAuthError();
990
  else showFetchError(err);
991
  }
 
548
  </div>
549
  </div>
550
 
551
+ <script type="module">
552
+ import { oauthLoginUrl, oauthHandleRedirectIfPresent } from "https://esm.sh/@huggingface/hub@1.3.1";
553
+
554
  // ─────────────────────────────────────────────────────────────
555
  // CONFIG
556
  // ─────────────────────────────────────────────────────────────
 
559
  const TREE_URL = `https://huggingface.co/api/buckets/${BUCKET}/tree/${PREFIX}`;
560
  const RESOLVE_BASE = `https://huggingface.co/buckets/${BUCKET}/resolve/`;
561
  const POLL_MS = 30_000;
562
+ const TOKEN_KEY = 'parameter_golf_hf_token';
563
+
564
+ // ─────────────────────────────────────────────────────────────
565
+ // OAUTH
566
+ // ─────────────────────────────────────────────────────────────
567
+ // If we just came back from the OAuth redirect, capture the token.
568
+ try {
569
+ const result = await oauthHandleRedirectIfPresent();
570
+ if (result && result.accessToken) {
571
+ sessionStorage.setItem(TOKEN_KEY, result.accessToken);
572
+ // Strip the OAuth fragment from the URL so reloads don't re-process it
573
+ history.replaceState(null, '', window.location.pathname + window.location.search);
574
+ }
575
+ } catch (e) {
576
+ console.warn('OAuth redirect handling failed:', e);
577
+ }
578
+
579
+ function getToken() {
580
+ return sessionStorage.getItem(TOKEN_KEY);
581
+ }
582
+ function clearToken() {
583
+ sessionStorage.removeItem(TOKEN_KEY);
584
+ }
585
+ async function startLogin() {
586
+ try {
587
+ const url = await oauthLoginUrl({ scopes: 'openid profile read-repos' });
588
+ // Preserve the user's current path so they come back here after auth
589
+ window.location.href = url + '&prompt=consent';
590
+ } catch (e) {
591
+ alert('Could not start sign-in: ' + (e.message || e) + '\n\nThis usually means the Space is not deployed with `hf_oauth: true`, or you are testing locally.');
592
+ }
593
+ }
594
 
595
  // ─────────────────────────────────────────────────────────────
596
  // STATE
 
740
  // ─────────────────────────────────────────────────────────────
741
  // FETCH
742
  // ─────────────────────────────────────────────────────────────
743
+ function authHeaders() {
744
+ const token = getToken();
745
+ return token ? { Authorization: `Bearer ${token}` } : {};
746
+ }
747
+
748
  async function fetchTree() {
749
+ const resp = await fetch(TREE_URL, { headers: authHeaders() });
750
  if (!resp.ok) {
751
  const err = new Error(`HTTP ${resp.status}`);
752
  err.status = resp.status;
 
756
  }
757
 
758
  async function fetchFile(path) {
759
+ const resp = await fetch(RESOLVE_BASE + path, { headers: authHeaders() });
760
+ if (!resp.ok) {
761
+ const err = new Error(`HTTP ${resp.status} for ${path}`);
762
+ err.status = resp.status;
763
+ throw err;
764
+ }
765
  return resp.text();
766
  }
767
 
 
973
  // ERROR / EMPTY STATES
974
  // ─────────────────────────────────────────────────────────────
975
  function showAuthError() {
976
+ setLiveStatus(false, 'SIGN IN');
977
+ clearToken();
978
  messagesEl.innerHTML = `
979
  <div class="state-screen">
980
+ <div class="icon">πŸ€—</div>
981
+ <h2>Sign in to view the chat</h2>
982
  <p>
983
+ This Space reads messages from the private
984
+ <a href="https://huggingface.co/buckets/${BUCKET}/tree/${PREFIX}" target="_blank">parameter-golf-collab bucket</a>.
985
+ Sign in with a Hugging Face account that has access to <code>ml-agent-explorers</code> to load the messages.
 
986
  </p>
987
+ <button id="loginBtn">Sign in with Hugging Face</button>
988
  </div>
989
  `;
990
+ document.getElementById('loginBtn').addEventListener('click', startLogin);
991
  }
992
  function showFetchError(err) {
993
  setLiveStatus(false, 'OFFLINE');
 
1009
  // INITIAL LOAD + POLL
1010
  // ─────────────────────────────────────────────────────────────
1011
  async function initialLoad() {
1012
+ // No token yet β†’ straight to the sign-in screen, don't even try fetching.
1013
+ if (!getToken()) {
1014
+ loadingScreen?.remove();
1015
+ showAuthError();
1016
+ return;
1017
+ }
1018
  try {
1019
  const fresh = await fetchAllMessages();
1020
  loadingScreen?.remove();
 
1036
  initialLoaded = true;
1037
  setLiveStatus(true, 'LIVE');
1038
  } catch (err) {
1039
+ loadingScreen?.remove();
1040
  if (err.status === 401 || err.status === 403) showAuthError();
1041
  else showFetchError(err);
1042
  }