m-newhauser commited on
Commit
99412aa
·
verified ·
1 Parent(s): 53395c6

Upload folder using huggingface_hub

Browse files
Files changed (4) hide show
  1. model.py +1 -1
  2. static/brand.css +58 -36
  3. static/index.html +7 -17
  4. static/strip.js +5 -4
model.py CHANGED
@@ -18,7 +18,7 @@ DEMO = {
18
  "title": "Sentiment and role, <em>per span</em>",
19
  "subtitle": "Document classification labels the whole review. GLiNER 2.5 attaches <strong>attributes to every entity</strong> it extracts.",
20
  "model_name": "GLiNER 2.5",
21
- "model_variant": "0.3B parameters · f32 · CPU",
22
  "code": (
23
  'schema = (model.create_schema()\n'
24
  ' .entities({"product": "A product mentioned in the text",\n'
 
18
  "title": "Sentiment and role, <em>per span</em>",
19
  "subtitle": "Document classification labels the whole review. GLiNER 2.5 attaches <strong>attributes to every entity</strong> it extracts.",
20
  "model_name": "GLiNER 2.5",
21
+ "model_variant": "0.3B parameters, f32, CPU",
22
  "code": (
23
  'schema = (model.create_schema()\n'
24
  ' .entities({"product": "A product mentioned in the text",\n'
static/brand.css CHANGED
@@ -61,31 +61,39 @@ body {
61
  /* ---- model strip ---- */
62
  .model-strip {
63
  display: flex; align-items: center; gap: 14px;
64
- margin: 18px 0 20px; padding: 11px 16px;
65
- background: var(--greige); border: 1px solid var(--ash); border-radius: var(--radius);
66
- }
67
- .model-glyph {
68
- width: 30px; height: 30px; border-radius: var(--radius-s); flex-shrink: 0;
69
- background: var(--ink);
70
- display: grid; place-items: center;
71
  }
72
- .model-glyph svg { width: 15px; height: 15px; color: var(--linen); }
73
- .model-name-row a { color: var(--ink); font-weight: 600; text-decoration: none; border-bottom: 1px solid var(--warm-gray); }
 
74
  .model-name-row a:hover { border-bottom-color: var(--orange-deep); color: var(--orange-deep); }
75
- .model-variant { margin-left: 8px; font-size: 12px; color: var(--ink-faint); font-family: var(--font-mono); }
76
- .load-block { margin-left: auto; min-width: 210px; }
77
- .load-meta { display: flex; justify-content: space-between; font-size: 12px; color: var(--ink-soft); margin-bottom: 5px; }
78
- #load-percent { font-family: var(--font-mono); }
79
- .load-track { height: 4px; background: var(--ash); border-radius: 99px; overflow: hidden; }
80
- #load-progress { display: block; height: 100%; width: 0; background: var(--orange); transition: width 400ms var(--ease-out); }
81
- .model-strip.is-ready #load-progress { background: var(--ok); }
82
- .model-strip.is-error #load-progress { background: var(--neg); }
83
-
84
- /* ready-state stats cluster (progress bar retires once loaded) */
85
- .model-stats { display: none; align-items: baseline; gap: 18px; font-size: 12px; color: var(--ink-faint); }
86
- .model-strip.is-ready .model-stats { display: flex; }
87
- .model-strip.is-ready .load-block { visibility: hidden; height: 0; min-width: 0; }
88
- .model-stats b { font-family: var(--font-mono); font-weight: 500; color: var(--ink); }
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  /* ---- workspace ---- */
91
  .workspace { display: grid; grid-template-columns: 5fr 7fr; gap: 16px; align-items: stretch; }
@@ -109,23 +117,37 @@ textarea, .editor {
109
  textarea:focus, .editor:focus { outline: 2px solid var(--ash); outline-offset: -2px; }
110
  textarea:focus-visible { outline: 2px solid var(--orange-deep); }
111
 
112
- /* ---- example chips (relocated above workspace) ---- */
113
- .examples-panel { margin: 0 0 14px; }
114
  .examples-label {
115
  font-size: 11px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
116
- color: var(--ink-faint); display: block; margin-bottom: 8px;
 
 
 
 
117
  }
118
- .example-list { display: flex; flex-wrap: wrap; gap: 8px; }
119
  .ex {
120
- font: inherit; font-size: 13px; font-weight: 500; color: var(--ink);
121
- background: var(--greige); border: 1px solid var(--ash); border-radius: 99px;
122
- padding: 6px 14px; cursor: pointer;
123
- transition: background 160ms var(--ease-out), border-color 160ms var(--ease-out), transform 80ms var(--ease-out);
124
- }
125
- .ex:hover { background: var(--ash); }
126
- .ex:active { transform: scale(0.97); }
127
- .ex:focus-visible { outline: 2px solid var(--orange-deep); outline-offset: 2px; }
128
- .ex.active { background: var(--ink); color: var(--linen); border-color: var(--ink); }
 
 
 
 
 
 
 
 
 
 
 
129
 
130
  /* ---- output body ---- */
131
  .output-body {
 
61
  /* ---- model strip ---- */
62
  .model-strip {
63
  display: flex; align-items: center; gap: 14px;
64
+ margin: 18px 0 20px; padding: 12px 16px;
65
+ background: transparent; border: 0; border-bottom: 1px solid var(--ash); border-radius: 0;
 
 
 
 
 
66
  }
67
+ .model-copy { flex: 1; min-width: 0; }
68
+ .model-name-row { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
69
+ .model-name-row a { color: var(--ink); font-weight: 600; text-decoration: none; font-size: 15px; border-bottom: 1px solid transparent; }
70
  .model-name-row a:hover { border-bottom-color: var(--orange-deep); color: var(--orange-deep); }
71
+ .model-variant { font-size: 12px; color: var(--ink-faint); font-family: var(--font-mono); }
72
+
73
+ .status-pill {
74
+ display: inline-flex; align-items: center; gap: 7px;
75
+ font-family: var(--font-mono); font-size: 11px; font-weight: 500;
76
+ color: var(--ink-soft); white-space: nowrap;
77
+ padding: 3px 9px; border: 1px solid var(--ash); border-radius: 4px;
78
+ background: var(--greige);
79
+ }
80
+ .status-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--warm-gray); flex-shrink: 0; }
81
+ .status-pill.is-ready { border-color: var(--ok-bg); color: var(--ok); }
82
+ .status-pill.is-ready .status-dot { background: var(--ok); }
83
+ .status-pill.is-error { border-color: rgba(168,69,69,0.3); color: var(--neg); }
84
+ .status-pill.is-error .status-dot { background: var(--neg); }
85
+ .status-pill.is-loading .status-dot { background: var(--orange); animation: pulse-dot 1.1s ease-in-out infinite; }
86
+ @keyframes pulse-dot { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }
87
+
88
+ .load-block { min-width: 180px; }
89
+ .load-track { height: 3px; background: transparent; border-radius: 99px; overflow: hidden; position: relative; }
90
+ .load-track::before { content: ""; position: absolute; inset: 0; background: var(--ash); border-radius: 99px; opacity: 0; transition: opacity 200ms; }
91
+ .model-strip.is-loading .load-track::before, .model-strip.is-preparing .load-track::before { opacity: 1; }
92
+ #load-progress { display: block; height: 100%; width: 0; background: var(--orange); border-radius: 99px; transition: width 400ms var(--ease-out); position: relative; }
93
+ .model-strip.is-ready #load-progress { width: 0; opacity: 0; }
94
+ .model-strip.is-ready #load-percent { display: none; }
95
+
96
+ /* hide percent counter entirely; status pill communicates state */
97
 
98
  /* ---- workspace ---- */
99
  .workspace { display: grid; grid-template-columns: 5fr 7fr; gap: 16px; align-items: stretch; }
 
117
  textarea:focus, .editor:focus { outline: 2px solid var(--ash); outline-offset: -2px; }
118
  textarea:focus-visible { outline: 2px solid var(--orange-deep); }
119
 
120
+ /* ---- example selector: indexed action rows (no pill chips) ---- */
121
+ .examples-panel { margin: 0 0 16px; }
122
  .examples-label {
123
  font-size: 11px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
124
+ color: var(--ink-faint); display: block; margin-bottom: 10px;
125
+ }
126
+ .example-list {
127
+ display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
128
+ border-top: 1px solid var(--ash); border-bottom: 1px solid var(--ash);
129
  }
 
130
  .ex {
131
+ font: inherit; text-align: left; background: transparent; border: 0;
132
+ border-right: 1px solid var(--ash);
133
+ padding: 12px 14px 11px; cursor: pointer;
134
+ display: flex; flex-direction: column; gap: 4px;
135
+ transition: background 140ms var(--ease-out);
136
+ position: relative;
137
+ }
138
+ .ex:last-child { border-right: 0; }
139
+ .ex:hover { background: var(--greige); }
140
+ .ex:active { transform: none; }
141
+ .ex:focus-visible { outline: 2px solid var(--orange-deep); outline-offset: -2px; z-index: 1; }
142
+ .ex .ex-idx { font-family: var(--font-mono); font-size: 11px; color: var(--ink-faint); }
143
+ .ex .ex-name { font-size: 13px; font-weight: 500; color: var(--ink); }
144
+ .ex.active { background: var(--greige); }
145
+ .ex.active .ex-idx { color: var(--orange-deep); }
146
+ .ex.active::after {
147
+ content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 2px;
148
+ background: var(--orange-deep);
149
+ }
150
+ @media (max-width: 860px) { .example-list { grid-template-columns: 1fr 1fr; } }
151
 
152
  /* ---- output body ---- */
153
  .output-body {
static/index.html CHANGED
@@ -18,27 +18,18 @@
18
  </header>
19
 
20
  <section class="model-strip is-loading" id="model-strip" aria-label="Model status">
21
- <span class="model-glyph" aria-hidden="true">
22
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
23
- <circle cx="5.5" cy="12" r="2.2"/><circle cx="18.5" cy="5" r="2.2"/><circle cx="18.5" cy="19" r="2.2"/>
24
- <path d="M7.3 10.8 16.6 6M7.3 13.2 16.6 18"/>
25
- </svg>
26
- </span>
27
  <div class="model-copy">
28
  <div class="model-name-row">
29
  <a id="model-link" href="#" target="_blank" rel="noopener"></a>
30
  <span class="model-variant" id="model-variant"></span>
31
  </div>
32
  </div>
33
- <div class="model-stats" aria-hidden="true">
34
- <span id="strip-state">Ready</span>
35
- </div>
 
36
  <div class="load-block">
37
- <div class="load-meta">
38
- <span id="status" role="status" aria-live="polite">Connecting...</span>
39
- <span id="load-percent">0%</span>
40
- </div>
41
- <div class="load-track"><span id="load-progress"></span></div>
42
  </div>
43
  </section>
44
 
@@ -221,7 +212,7 @@ $("output").addEventListener("click", (e) => {
221
  cfg.examples.forEach((ex, i) => {
222
  const b = document.createElement("button");
223
  b.type = "button"; b.className = "ex" + (i === 0 ? " active" : "");
224
- b.textContent = ex.chip;
225
  b.addEventListener("click", () => {
226
  document.querySelectorAll(".ex").forEach((x) => x.classList.toggle("active", x === b));
227
  $("input").value = ex.text;
@@ -233,8 +224,7 @@ $("output").addEventListener("click", (e) => {
233
  setEmpty("idle");
234
  if (cfg.examples[0]) $("input").value = cfg.examples[0].text;
235
  READY = await waitForServer();
236
- stripSet(READY ? "Model ready" : "Model unavailable", READY ? "ready" : "error", 100);
237
- $("strip-state").textContent = READY ? "Ready" : "Unavailable";
238
  if (READY) infer();
239
  })();
240
  </script>
 
18
  </header>
19
 
20
  <section class="model-strip is-loading" id="model-strip" aria-label="Model status">
 
 
 
 
 
 
21
  <div class="model-copy">
22
  <div class="model-name-row">
23
  <a id="model-link" href="#" target="_blank" rel="noopener"></a>
24
  <span class="model-variant" id="model-variant"></span>
25
  </div>
26
  </div>
27
+ <span class="status-pill is-loading" id="status-pill">
28
+ <span class="status-dot" aria-hidden="true"></span>
29
+ <span id="status" role="status" aria-live="polite">Connecting</span>
30
+ </span>
31
  <div class="load-block">
32
+ <div class="load-track" aria-hidden="true"><span id="load-progress"></span></div>
 
 
 
 
33
  </div>
34
  </section>
35
 
 
212
  cfg.examples.forEach((ex, i) => {
213
  const b = document.createElement("button");
214
  b.type = "button"; b.className = "ex" + (i === 0 ? " active" : "");
215
+ b.innerHTML = `<span class="ex-idx">${String(i + 1).padStart(2, "0")}</span><span class="ex-name">${esc(ex.chip)}</span>`;
216
  b.addEventListener("click", () => {
217
  document.querySelectorAll(".ex").forEach((x) => x.classList.toggle("active", x === b));
218
  $("input").value = ex.text;
 
224
  setEmpty("idle");
225
  if (cfg.examples[0]) $("input").value = cfg.examples[0].text;
226
  READY = await waitForServer();
227
+ stripSet(READY ? "Model ready" : "Model unavailable", READY ? "ready" : "error", READY ? 100 : 0);
 
228
  if (READY) infer();
229
  })();
230
  </script>
static/strip.js CHANGED
@@ -1,4 +1,4 @@
1
- // strip.js shared plumbing for every GLiNER 2.5 demo page.
2
  // 1. __sign shim: private HF Spaces sign the iframe URL; Safari/incognito block
3
  // the third-party cookie, so carry the token on same-origin API requests.
4
  // 2. readiness poll: drives the model strip (loading -> preparing -> ready).
@@ -22,22 +22,23 @@
22
 
23
  function stripSet(message, tone, pct) {
24
  const strip = document.getElementById("model-strip");
 
25
  document.getElementById("status").textContent = message;
26
  strip.className = `model-strip is-${tone}`;
 
27
  if (pct != null) {
28
  document.getElementById("load-progress").style.width = `${pct}%`;
29
- document.getElementById("load-percent").textContent = `${Math.round(pct)}%`;
30
  }
31
  }
32
 
33
  async function waitForServer() {
34
- stripSet("Connecting to server...", "loading", 12);
35
  for (let attempt = 0; attempt < 300; attempt++) {
36
  try {
37
  const r = await fetch("api/ready", { cache: "no-store" });
38
  if (r.ok && (await r.json()).ready) return true;
39
  } catch (e) { /* still starting */ }
40
- stripSet("Warming up the model...", "preparing", Math.min(92, 12 + attempt * 4));
41
  await new Promise((r) => setTimeout(r, 1000));
42
  }
43
  return false;
 
1
+ // strip.js - shared plumbing for every GLiNER 2.5 demo page.
2
  // 1. __sign shim: private HF Spaces sign the iframe URL; Safari/incognito block
3
  // the third-party cookie, so carry the token on same-origin API requests.
4
  // 2. readiness poll: drives the model strip (loading -> preparing -> ready).
 
22
 
23
  function stripSet(message, tone, pct) {
24
  const strip = document.getElementById("model-strip");
25
+ const pill = document.getElementById("status-pill");
26
  document.getElementById("status").textContent = message;
27
  strip.className = `model-strip is-${tone}`;
28
+ if (pill) pill.className = `status-pill is-${tone}`;
29
  if (pct != null) {
30
  document.getElementById("load-progress").style.width = `${pct}%`;
 
31
  }
32
  }
33
 
34
  async function waitForServer() {
35
+ stripSet("Connecting", "loading", 12);
36
  for (let attempt = 0; attempt < 300; attempt++) {
37
  try {
38
  const r = await fetch("api/ready", { cache: "no-store" });
39
  if (r.ok && (await r.json()).ready) return true;
40
  } catch (e) { /* still starting */ }
41
+ stripSet("Warming up", "loading", Math.min(92, 12 + attempt * 4));
42
  await new Promise((r) => setTimeout(r, 1000));
43
  }
44
  return false;