BoxOfColors Claude Sonnet 4.6 commited on
Commit
03cbad9
·
1 Parent(s): 8b3b191

Add HF token input for ZeroGPU Pro quota on regen

Browse files

Users can paste their HF token in the Settings accordion so that
segment regen calls use Authorization: Bearer <token> — the documented
way for ZeroGPU to attribute quota to a Pro account. Falls back to
x-ip-token relay if no token is provided. Quota now correctly debits
the logged-in user's Pro pool instead of the shared anonymous pool.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +48 -17
app.py CHANGED
@@ -2133,13 +2133,26 @@ _GLOBAL_JS = """
2133
  console.warn('[fireRegen] fn_index not found for api_name:', apiName);
2134
  return;
2135
  }
2136
- // Fetch a fresh x-ip-token immediately before queuing (JWT expires ~170s,
2137
- // so we always grab a new one to ensure Pro quota attribution).
2138
- _fetchIpToken().then(function(ipToken) {
 
 
 
 
 
 
2139
  var regenHeaders = {'Content-Type': 'application/json'};
2140
- if (ipToken) { regenHeaders['x-ip-token'] = ipToken; console.log('[fireRegen] using fresh x-ip-token, len:', ipToken.length); }
2141
- else { console.warn('[fireRegen] no x-ip-token available, regen may use anonymous quota'); }
2142
- return fetch('/gradio_api/queue/join', {
 
 
 
 
 
 
 
2143
  method: 'POST',
2144
  credentials: 'include',
2145
  headers: regenHeaders,
@@ -2150,18 +2163,23 @@ _GLOBAL_JS = """
2150
  event_data: null,
2151
  trigger_id: null
2152
  })
 
 
 
 
 
 
 
 
 
2153
  });
2154
- }).then(function(r) { return r.json(); }).then(function(j) {
2155
- if (!j.event_id) { console.error('[fireRegen] no event_id:', j); return; }
2156
- console.log('[fireRegen] queued, event_id:', j.event_id);
2157
- // Subscribe to SSE stream and apply outputs when ready
2158
- _listenAndApply(j.event_id, slot_id, seg_idx, _preRegenWaveHtml, _preRegenVideoSrc);
2159
- }).catch(function(e) {
2160
- console.error('[fireRegen] fetch error:', e);
2161
- if (lbl) lbl.textContent = 'Error — see console';
2162
- var sb = document.getElementById('wf_statusbar_' + slot_id);
2163
- if (sb) { sb.style.color = '#e05252'; sb.textContent = '\u26a0 Request failed: ' + e.message; }
2164
- });
2165
  }
2166
 
2167
  // Subscribe to Gradio SSE stream for an event and apply outputs to DOM.
@@ -2341,6 +2359,19 @@ _GLOBAL_JS = """
2341
  """
2342
 
2343
  with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
2344
  gr.Markdown(
2345
  "# Generate Audio for Video\n"
2346
  "Choose a model and upload a video to generate synchronized audio.\n\n"
 
2133
  console.warn('[fireRegen] fn_index not found for api_name:', apiName);
2134
  return;
2135
  }
2136
+ // Build auth headers for the regen call.
2137
+ // Prefer a user-supplied HF token (Authorization: Bearer) which is the
2138
+ // documented way for ZeroGPU to attribute quota to a logged-in Pro account.
2139
+ // Fall back to the x-ip-token relay approach if no HF token is provided.
2140
+ var userHfToken = '';
2141
+ var hfTokenEl = document.getElementById('hf_token_input');
2142
+ if (hfTokenEl) { var inp = hfTokenEl.querySelector('input,textarea'); if (inp) userHfToken = (inp.value || '').trim(); }
2143
+
2144
+ var _doRegen = function(ipToken) {
2145
  var regenHeaders = {'Content-Type': 'application/json'};
2146
+ if (userHfToken) {
2147
+ regenHeaders['Authorization'] = 'Bearer ' + userHfToken;
2148
+ console.log('[fireRegen] using HF token for Pro quota attribution');
2149
+ } else if (ipToken) {
2150
+ regenHeaders['x-ip-token'] = ipToken;
2151
+ console.log('[fireRegen] using fresh x-ip-token, len:', ipToken.length);
2152
+ } else {
2153
+ console.warn('[fireRegen] no auth available, regen may use anonymous quota');
2154
+ }
2155
+ fetch('/gradio_api/queue/join', {
2156
  method: 'POST',
2157
  credentials: 'include',
2158
  headers: regenHeaders,
 
2163
  event_data: null,
2164
  trigger_id: null
2165
  })
2166
+ }).then(function(r) { return r.json(); }).then(function(j) {
2167
+ if (!j.event_id) { console.error('[fireRegen] no event_id:', j); return; }
2168
+ console.log('[fireRegen] queued, event_id:', j.event_id);
2169
+ _listenAndApply(j.event_id, slot_id, seg_idx, _preRegenWaveHtml, _preRegenVideoSrc);
2170
+ }).catch(function(e) {
2171
+ console.error('[fireRegen] fetch error:', e);
2172
+ if (lbl) lbl.textContent = 'Error — see console';
2173
+ var sb = document.getElementById('wf_statusbar_' + slot_id);
2174
+ if (sb) { sb.style.color = '#e05252'; sb.textContent = '\u26a0 Request failed: ' + e.message; }
2175
  });
2176
+ };
2177
+ // If user provided HF token, skip x-ip-token relay (token is sufficient)
2178
+ if (userHfToken) {
2179
+ _doRegen('');
2180
+ } else {
2181
+ _fetchIpToken().then(_doRegen);
2182
+ }
 
 
 
 
2183
  }
2184
 
2185
  // Subscribe to Gradio SSE stream for an event and apply outputs to DOM.
 
2359
  """
2360
 
2361
  with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) as demo:
2362
+ with gr.Accordion("⚙️ Settings (optional)", open=False):
2363
+ gr.Markdown(
2364
+ "**HF Token** — Paste your [Hugging Face token](https://huggingface.co/settings/tokens) here so that "
2365
+ "segment regeneration uses your own ZeroGPU quota (PRO = 25 min/day) instead of the shared free pool. "
2366
+ "The token is stored only in your browser and never sent anywhere except the Space's own API."
2367
+ )
2368
+ hf_token_input = gr.Textbox(
2369
+ label="Hugging Face Token (optional)",
2370
+ placeholder="hf_...",
2371
+ type="password",
2372
+ elem_id="hf_token_input",
2373
+ max_lines=1,
2374
+ )
2375
  gr.Markdown(
2376
  "# Generate Audio for Video\n"
2377
  "Choose a model and upload a video to generate synchronized audio.\n\n"