codex-repair commited on
Commit
1bc7676
·
1 Parent(s): c5ab458

Restore VisA startup when dataset server is unavailable

Browse files
.gitattributes DELETED
@@ -1 +0,0 @@
1
- vendor/hyperview-0.6.3.dev0+g1ddcd10b5.d20260607-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
 
 
.hyperview/extensions/manufacturing-readout/panel.js CHANGED
@@ -18,9 +18,6 @@ const colors = {
18
  goodBg: "#132018",
19
  accent: "#8fb8ff",
20
  error: "#fca5a5",
21
- warningBg: "#3b2f12",
22
- warningBorder: "#92400e",
23
- warningText: "#fde68a",
24
  };
25
 
26
  function pretty(value) {
@@ -485,7 +482,6 @@ export default function ManufacturingPanel() {
485
  const models = normalizeModels(props.models);
486
  const examples = Array.isArray(props.examples) ? props.examples : [];
487
  const primaryExample = examples.find((item) => item.id === "fryum") || examples[0] || null;
488
- const warnings = Array.isArray(props.warnings) ? props.warnings : [];
489
  const [loadingKey, setLoadingKey] = React.useState(null);
490
  const [panelError, setPanelError] = React.useState(null);
491
  const [activeChoice, setActiveChoice] = React.useState(null);
@@ -604,24 +600,6 @@ export default function ManufacturingPanel() {
604
  panelError,
605
  )
606
  : null,
607
- warnings.map((warning, index) =>
608
- React.createElement(
609
- "div",
610
- {
611
- key: index,
612
- style: {
613
- border: `1px solid ${colors.warningBorder}`,
614
- background: colors.warningBg,
615
- color: colors.warningText,
616
- borderRadius: 5,
617
- padding: 8,
618
- fontSize: 11,
619
- lineHeight: 1.35,
620
- },
621
- },
622
- warning,
623
- ),
624
- ),
625
  React.createElement(StrengthTable, { rows: Array.isArray(props.strengthRows) ? props.strengthRows : [] }),
626
  ),
627
  );
 
18
  goodBg: "#132018",
19
  accent: "#8fb8ff",
20
  error: "#fca5a5",
 
 
 
21
  };
22
 
23
  function pretty(value) {
 
482
  const models = normalizeModels(props.models);
483
  const examples = Array.isArray(props.examples) ? props.examples : [];
484
  const primaryExample = examples.find((item) => item.id === "fryum") || examples[0] || null;
 
485
  const [loadingKey, setLoadingKey] = React.useState(null);
486
  const [panelError, setPanelError] = React.useState(null);
487
  const [activeChoice, setActiveChoice] = React.useState(null);
 
600
  panelError,
601
  )
602
  : null,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  React.createElement(StrengthTable, { rows: Array.isArray(props.strengthRows) ? props.strengthRows : [] }),
604
  ),
605
  );
README.md CHANGED
@@ -63,6 +63,4 @@ The Docker image installs the bundled latest HyperView wheel for this repo and
63
  uses HyperView's public dataset, UI, and panel command APIs. Hyper3-CLIP loads
64
  through the public `hyper-models` provider catalog entry for the gated
65
  `hyper3labs/hyper3-clip-v0.5` model repository. The Space needs an `HF_TOKEN`
66
- secret with access to that model. If unavailable, the Space can start with a
67
- clearly labeled CLIP fallback unless `HYPERVIEW_ALLOW_CANDIDATE_FALLBACK=0` is
68
- set.
 
63
  uses HyperView's public dataset, UI, and panel command APIs. Hyper3-CLIP loads
64
  through the public `hyper-models` provider catalog entry for the gated
65
  `hyper3labs/hyper3-clip-v0.5` model repository. The Space needs an `HF_TOKEN`
66
+ secret with access to that model; startup fails if the model cannot be loaded.
 
 
__pycache__/demo.cpython-311.pyc ADDED
Binary file (30.7 kB). View file
 
__pycache__/demo.cpython-314.pyc ADDED
Binary file (30.1 kB). View file
 
demo.py CHANGED
@@ -29,18 +29,14 @@ EXTENSION_DIR = SPACE_DIR / ".hyperview" / "extensions" / "manufacturing-readout
29
  SAMPLES_PER_CATEGORY = int(os.environ.get("VISA_SAMPLES_PER_CATEGORY", "4"))
30
  TRAIN_FRACTION = float(os.environ.get("VISA_TRAIN_FRACTION", "0.5"))
31
  IMAGE_MAX_SIZE = (640, 640)
 
 
32
  FORCE_SAMPLE_REFRESH = os.environ.get("HYPERVIEW_VISA_FORCE_REFRESH", "").lower() in {
33
  "1",
34
  "true",
35
  "yes",
36
  }
37
- ALLOW_CANDIDATE_FALLBACK = os.environ.get("HYPERVIEW_ALLOW_CANDIDATE_FALLBACK", "1").lower() in {
38
- "1",
39
- "true",
40
- "yes",
41
- }
42
- RUNTIME_WARNINGS: list[str] = []
43
-
44
  VISA_CATEGORIES = (
45
  "candle",
46
  "capsules",
@@ -123,9 +119,11 @@ def readable(value: str) -> str:
123
 
124
 
125
  def fetch_rows(split: str, count: int) -> list[dict[str, Any]]:
 
 
126
  params = urllib.parse.urlencode(
127
  {
128
- "dataset": "BrachioLab/visa",
129
  "config": "default",
130
  "split": split,
131
  "offset": 0,
@@ -134,22 +132,45 @@ def fetch_rows(split: str, count: int) -> list[dict[str, Any]]:
134
  )
135
  url = f"https://datasets-server.huggingface.co/rows?{params}"
136
  last_error: Exception | None = None
137
- for attempt in range(1, 5):
138
- try:
139
- with urllib.request.urlopen(url, timeout=60) as response:
140
- payload = json.loads(response.read().decode("utf-8"))
141
- break
142
- except Exception as exc:
143
- last_error = exc
144
- if attempt == 4:
145
- raise
146
- time.sleep(1.5 * attempt)
147
- else:
148
- raise RuntimeError(f"Could not fetch VisA split {split}") from last_error
149
- rows = [item["row"] for item in payload["rows"]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  if len(rows) < count:
151
- raise RuntimeError(f"Split {split} returned {len(rows)} rows for requested count {count}")
152
- return rows[:count]
153
 
154
 
155
  def local_records(category: str, split_type: str, count: int) -> list[dict[str, Any]]:
@@ -175,11 +196,16 @@ def local_records(category: str, split_type: str, count: int) -> list[dict[str,
175
  return records[:count]
176
 
177
 
178
- def save_url_image(url: str, destination: Path) -> None:
179
  if destination.exists() and destination.stat().st_size > 0:
180
  return
181
- with urllib.request.urlopen(url, timeout=60) as response:
182
- image = Image.open(io.BytesIO(response.read()))
 
 
 
 
 
183
  image = ImageOps.exif_transpose(image).convert("RGB")
184
  image.thumbnail(IMAGE_MAX_SIZE, Image.Resampling.LANCZOS)
185
  tmp_path = destination.with_suffix(destination.suffix + ".tmp")
@@ -202,10 +228,11 @@ def select_visa_records() -> list[dict[str, Any]]:
202
  split_name = f"{category}.{split_type}"
203
  rows = fetch_rows(split_name, count)
204
  for row_index, row in enumerate(rows):
 
205
  records.append(
206
  {
207
  "row_index": row_index,
208
- "image_url": row["image"]["src"],
209
  "local_path": None,
210
  "category": category,
211
  "family": FAMILY_BY_CATEGORY[category],
@@ -226,8 +253,8 @@ def add_visa_samples(dataset: hv.Dataset) -> None:
226
  for record in select_visa_records():
227
  sample_id = safe_sample_id(record["category"], record["split_name"], record["row_index"], record["defect_label"])
228
  destination = Path(record["local_path"]) if record.get("local_path") else media_dir / f"{sample_id}.jpg"
229
- if record.get("image_url"):
230
- save_url_image(record["image_url"], destination)
231
  metadata = {
232
  "sku": record["category"],
233
  "product_family": record["family"],
@@ -257,36 +284,12 @@ def ensure_layouts(dataset: hv.Dataset) -> dict[str, str]:
257
  layouts: dict[str, str] = {}
258
  for spec in MODEL_SPECS:
259
  print(f"Ensuring {spec['display_name']} embeddings...", flush=True)
260
- try:
261
- space_key = dataset.compute_embeddings(
262
- model=spec["model"],
263
- provider=spec["provider"],
264
- batch_size=32,
265
- show_progress=True,
266
- )
267
- except Exception as exc:
268
- if spec["key"] == "candidate" and ALLOW_CANDIDATE_FALLBACK and "clip" in layouts:
269
- warning = (
270
- f"Hyper3-CLIP embeddings are unavailable ({type(exc).__name__}: {exc}). "
271
- "Showing the CLIP layout as a clearly labeled fallback so the Space can start."
272
- )
273
- print(warning, flush=True)
274
- RUNTIME_WARNINGS.append(warning)
275
- fallback_layout_key = layouts["clip"]
276
- spec.update(
277
- {
278
- "display_name": "Hyper3-CLIP unavailable (CLIP fallback)",
279
- "button_label": "CLIP fallback query",
280
- "geometry": MODEL_SPECS[0]["geometry"],
281
- "layout_dimension": MODEL_SPECS[0]["layout_dimension"],
282
- "panel_title": "Hyper3-CLIP unavailable - showing CLIP fallback",
283
- "fallback": True,
284
- "layout_key": fallback_layout_key,
285
- }
286
- )
287
- layouts[spec["key"]] = fallback_layout_key
288
- continue
289
- raise
290
  print(f"Ensuring {spec['display_name']} layout...", flush=True)
291
  layout_key = dataset.compute_visualization(
292
  space_key=space_key,
@@ -376,16 +379,10 @@ def build_examples(dataset: hv.Dataset) -> list[dict[str, Any]]:
376
  if sample.metadata.get("workflow_role") == "inspection_query":
377
  by_category.setdefault(sample.label, sample)
378
  examples = []
379
- candidate_is_fallback = any(spec["key"] == "candidate" and spec.get("fallback") for spec in MODEL_SPECS)
380
  for category, family_title in PREFERRED_EXAMPLES:
381
  sample = by_category.get(category)
382
  if sample is None:
383
  continue
384
- candidate_text = (
385
- "Hyper3-CLIP is unavailable in this runtime, so this button shows the CLIP fallback neighborhood."
386
- if candidate_is_fallback
387
- else "Inspect whether normal references and same-SKU examples stay ahead of wrong-line neighbors."
388
- )
389
  examples.append(
390
  {
391
  "id": category,
@@ -399,7 +396,7 @@ def build_examples(dataset: hv.Dataset) -> list[dict[str, Any]]:
399
  **reference_summary(dataset, sample.id, "clip"),
400
  },
401
  "candidate": {
402
- "text": candidate_text,
403
  **reference_summary(dataset, sample.id, "candidate"),
404
  },
405
  },
@@ -461,7 +458,6 @@ def build_demo_view(dataset: hv.Dataset, layouts: dict[str, str]) -> hv.ui.View:
461
  "models": model_panel_props(layouts),
462
  "examples": build_examples(dataset),
463
  "strengthRows": category_strength_rows(dataset),
464
- "warnings": RUNTIME_WARNINGS,
465
  },
466
  ),
467
  hv.ui.Samples(
 
29
  SAMPLES_PER_CATEGORY = int(os.environ.get("VISA_SAMPLES_PER_CATEGORY", "4"))
30
  TRAIN_FRACTION = float(os.environ.get("VISA_TRAIN_FRACTION", "0.5"))
31
  IMAGE_MAX_SIZE = (640, 640)
32
+ VISA_DATASET_ID = "BrachioLab/visa"
33
+ VISA_DATASET_REVISION = "d185c42584b49f1df81fe12bde627559ed88d483"
34
  FORCE_SAMPLE_REFRESH = os.environ.get("HYPERVIEW_VISA_FORCE_REFRESH", "").lower() in {
35
  "1",
36
  "true",
37
  "yes",
38
  }
39
+ DATASET_SERVER_UNAVAILABLE = False
 
 
 
 
 
 
40
  VISA_CATEGORIES = (
41
  "candle",
42
  "capsules",
 
119
 
120
 
121
  def fetch_rows(split: str, count: int) -> list[dict[str, Any]]:
122
+ global DATASET_SERVER_UNAVAILABLE
123
+
124
  params = urllib.parse.urlencode(
125
  {
126
+ "dataset": VISA_DATASET_ID,
127
  "config": "default",
128
  "split": split,
129
  "offset": 0,
 
132
  )
133
  url = f"https://datasets-server.huggingface.co/rows?{params}"
134
  last_error: Exception | None = None
135
+ if not DATASET_SERVER_UNAVAILABLE:
136
+ for attempt in range(1, 5):
137
+ try:
138
+ with urllib.request.urlopen(url, timeout=60) as response:
139
+ payload = json.loads(response.read().decode("utf-8"))
140
+ rows = [item["row"] for item in payload["rows"]]
141
+ if len(rows) < count:
142
+ raise RuntimeError(f"Split {split} returned {len(rows)} rows for requested count {count}")
143
+ return rows[:count]
144
+ except Exception as exc:
145
+ last_error = exc
146
+ if attempt < 4:
147
+ time.sleep(1.5 * attempt)
148
+ DATASET_SERVER_UNAVAILABLE = True
149
+ print(
150
+ f"VisA dataset-server rows unavailable ({type(last_error).__name__}: {last_error}); "
151
+ "falling back to the pinned Hub dataset.",
152
+ flush=True,
153
+ )
154
+
155
+ try:
156
+ from datasets import load_dataset
157
+
158
+ stream = load_dataset(
159
+ VISA_DATASET_ID,
160
+ split=split,
161
+ revision=VISA_DATASET_REVISION,
162
+ streaming=True,
163
+ )
164
+ rows = []
165
+ for row in stream:
166
+ rows.append(row)
167
+ if len(rows) >= count:
168
+ break
169
+ except Exception as exc:
170
+ raise RuntimeError(f"Could not fetch pinned VisA split {split} from the Hub") from exc
171
  if len(rows) < count:
172
+ raise RuntimeError(f"Split {split} returned {len(rows)} rows for requested count {count}") from last_error
173
+ return rows
174
 
175
 
176
  def local_records(category: str, split_type: str, count: int) -> list[dict[str, Any]]:
 
196
  return records[:count]
197
 
198
 
199
+ def save_image(source: Any, destination: Path) -> None:
200
  if destination.exists() and destination.stat().st_size > 0:
201
  return
202
+ if isinstance(source, str):
203
+ with urllib.request.urlopen(source, timeout=60) as response:
204
+ image = Image.open(io.BytesIO(response.read()))
205
+ elif isinstance(source, Image.Image):
206
+ image = source
207
+ else:
208
+ raise TypeError(f"Unsupported VisA image source: {type(source).__name__}")
209
  image = ImageOps.exif_transpose(image).convert("RGB")
210
  image.thumbnail(IMAGE_MAX_SIZE, Image.Resampling.LANCZOS)
211
  tmp_path = destination.with_suffix(destination.suffix + ".tmp")
 
228
  split_name = f"{category}.{split_type}"
229
  rows = fetch_rows(split_name, count)
230
  for row_index, row in enumerate(rows):
231
+ image = row["image"]
232
  records.append(
233
  {
234
  "row_index": row_index,
235
+ "image_source": image["src"] if isinstance(image, dict) else image,
236
  "local_path": None,
237
  "category": category,
238
  "family": FAMILY_BY_CATEGORY[category],
 
253
  for record in select_visa_records():
254
  sample_id = safe_sample_id(record["category"], record["split_name"], record["row_index"], record["defect_label"])
255
  destination = Path(record["local_path"]) if record.get("local_path") else media_dir / f"{sample_id}.jpg"
256
+ if record.get("image_source") is not None:
257
+ save_image(record["image_source"], destination)
258
  metadata = {
259
  "sku": record["category"],
260
  "product_family": record["family"],
 
284
  layouts: dict[str, str] = {}
285
  for spec in MODEL_SPECS:
286
  print(f"Ensuring {spec['display_name']} embeddings...", flush=True)
287
+ space_key = dataset.compute_embeddings(
288
+ model=spec["model"],
289
+ provider=spec["provider"],
290
+ batch_size=32,
291
+ show_progress=True,
292
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  print(f"Ensuring {spec['display_name']} layout...", flush=True)
294
  layout_key = dataset.compute_visualization(
295
  space_key=space_key,
 
379
  if sample.metadata.get("workflow_role") == "inspection_query":
380
  by_category.setdefault(sample.label, sample)
381
  examples = []
 
382
  for category, family_title in PREFERRED_EXAMPLES:
383
  sample = by_category.get(category)
384
  if sample is None:
385
  continue
 
 
 
 
 
386
  examples.append(
387
  {
388
  "id": category,
 
396
  **reference_summary(dataset, sample.id, "clip"),
397
  },
398
  "candidate": {
399
+ "text": "Inspect whether normal references and same-SKU examples stay ahead of wrong-line neighbors.",
400
  **reference_summary(dataset, sample.id, "candidate"),
401
  },
402
  },
 
458
  "models": model_panel_props(layouts),
459
  "examples": build_examples(dataset),
460
  "strengthRows": category_strength_rows(dataset),
 
461
  },
462
  ),
463
  hv.ui.Samples(