ryanhlewis commited on
Commit
97524a3
·
verified ·
1 Parent(s): 797e381

Fix static tokenizer loading from Hugging Face model repo

Browse files
Files changed (3) hide show
  1. README.md +1 -1
  2. space-config.js +1 -1
  3. static-app.js +50 -15
README.md CHANGED
@@ -14,4 +14,4 @@ Static browser-only FLUX.2 Klein 4B inference through WebGPU.
14
 
15
  The Space serves a small HTML/JS app. Model files are fetched from
16
  [ryanhlewis/flux2-klein-4b-webgpu-lowbit](https://huggingface.co/ryanhlewis/flux2-klein-4b-webgpu-lowbit)
17
- and generation runs in the user's browser.
 
14
 
15
  The Space serves a small HTML/JS app. Model files are fetched from
16
  [ryanhlewis/flux2-klein-4b-webgpu-lowbit](https://huggingface.co/ryanhlewis/flux2-klein-4b-webgpu-lowbit)
17
+ and generation runs in the user's browser.
space-config.js CHANGED
@@ -1,3 +1,3 @@
1
  globalThis.FLUX2_MODEL_BASE_URL = "https://huggingface.co/ryanhlewis/flux2-klein-4b-webgpu-lowbit/resolve/main";
2
  globalThis.FLUX2_RUNTIME_BASE_URL = globalThis.FLUX2_MODEL_BASE_URL;
3
- globalThis.FLUX2_CUSTOM_KERNEL_BASE_URL = `${globalThis.FLUX2_MODEL_BASE_URL}/custom_lowbit`;
 
1
  globalThis.FLUX2_MODEL_BASE_URL = "https://huggingface.co/ryanhlewis/flux2-klein-4b-webgpu-lowbit/resolve/main";
2
  globalThis.FLUX2_RUNTIME_BASE_URL = globalThis.FLUX2_MODEL_BASE_URL;
3
+ globalThis.FLUX2_CUSTOM_KERNEL_BASE_URL = `${globalThis.FLUX2_MODEL_BASE_URL}/custom_lowbit`;
static-app.js CHANGED
@@ -129,12 +129,52 @@ function configuredCustomKernelBaseUrl(modelBaseUrl = configuredModelBaseUrl(),
129
  function resolveAssetUrl(baseUrl, path) {
130
  return new URL(path, new URL(withTrailingSlash(baseUrl), window.location.href)).toString();
131
  }
132
-
133
- function setStatus(lines, isError = false) {
134
- const text = Array.isArray(lines) ? lines.filter(Boolean).join("\n") : String(lines);
135
- statusEl.textContent = text;
136
- statusEl.classList.toggle("error", Boolean(isError));
137
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
  function setButtonDisabled(button, disabled) {
140
  if (button) button.disabled = disabled;
@@ -438,16 +478,11 @@ function maskFromLength(length, seqLen) {
438
  async function loadTokenizer() {
439
  if (tokenizerPromise) return tokenizerPromise;
440
  const modelBaseUrl = configuredModelBaseUrl();
441
- const remoteTokenizer = /^https?:\/\//i.test(modelBaseUrl);
442
- env.allowLocalModels = true;
443
- env.allowRemoteModels = remoteTokenizer;
444
  env.localModelPath = "/";
445
- const tokenizerPath = remoteTokenizer
446
- ? resolveAssetUrl(modelBaseUrl, "tokenizer")
447
- : "models/tokenizer";
448
- tokenizerPromise = AutoTokenizer.from_pretrained(tokenizerPath, {
449
- local_files_only: !remoteTokenizer,
450
- });
451
  return tokenizerPromise;
452
  }
453
 
 
129
  function resolveAssetUrl(baseUrl, path) {
130
  return new URL(path, new URL(withTrailingSlash(baseUrl), window.location.href)).toString();
131
  }
132
+
133
+ function huggingFaceResolveSpec(baseUrl) {
134
+ let url;
135
+ try {
136
+ url = new URL(baseUrl);
137
+ } catch {
138
+ return null;
139
+ }
140
+ if (!/^https?:$/i.test(url.protocol)) return null;
141
+ if (!/^(huggingface\.co|hf\.co)$/i.test(url.hostname)) return null;
142
+ const parts = url.pathname.split("/").filter(Boolean);
143
+ const resolveIndex = parts.indexOf("resolve");
144
+ if (resolveIndex < 2 || resolveIndex + 1 >= parts.length) return null;
145
+ return {
146
+ repoId: `${parts[0]}/${parts[1]}`,
147
+ revision: decodeURIComponent(parts[resolveIndex + 1]),
148
+ };
149
+ }
150
+
151
+ function tokenizerLoadSpec(modelBaseUrl) {
152
+ const hfSpec = huggingFaceResolveSpec(modelBaseUrl);
153
+ if (hfSpec) {
154
+ return {
155
+ source: hfSpec.repoId,
156
+ remote: true,
157
+ options: {
158
+ local_files_only: false,
159
+ revision: hfSpec.revision || "main",
160
+ },
161
+ };
162
+ }
163
+ const remote = /^https?:\/\//i.test(modelBaseUrl);
164
+ return {
165
+ source: remote ? resolveAssetUrl(modelBaseUrl, "tokenizer") : "models/tokenizer",
166
+ remote,
167
+ options: {
168
+ local_files_only: !remote,
169
+ },
170
+ };
171
+ }
172
+
173
+ function setStatus(lines, isError = false) {
174
+ const text = Array.isArray(lines) ? lines.filter(Boolean).join("\n") : String(lines);
175
+ statusEl.textContent = text;
176
+ statusEl.classList.toggle("error", Boolean(isError));
177
+ }
178
 
179
  function setButtonDisabled(button, disabled) {
180
  if (button) button.disabled = disabled;
 
478
  async function loadTokenizer() {
479
  if (tokenizerPromise) return tokenizerPromise;
480
  const modelBaseUrl = configuredModelBaseUrl();
481
+ const tokenizerSpec = tokenizerLoadSpec(modelBaseUrl);
482
+ env.allowLocalModels = !tokenizerSpec.remote;
483
+ env.allowRemoteModels = tokenizerSpec.remote;
484
  env.localModelPath = "/";
485
+ tokenizerPromise = AutoTokenizer.from_pretrained(tokenizerSpec.source, tokenizerSpec.options);
 
 
 
 
 
486
  return tokenizerPromise;
487
  }
488