File size: 3,187 Bytes
033d95e
 
01b427f
033d95e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16ced5b
 
 
033d95e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
const vars = globalThis.huggingface?.variables || {};
const datasetId = vars.HF_DATASET_ID || "marijanic/map-annotation-tool-data";
const revision = vars.HF_DATASET_REVISION || "ddf36b53ec5e8eeefcfc41d9923f97d5ec7ac62f";
const manifestName = vars.FIGURE_MANIFEST_PATH || "figures.jsonl";
const datasetBase = `https://huggingface.co/datasets/${datasetId}/resolve/${revision}/`;
const root = document.getElementById("mat-root");

const encodePath = path => path.split("/").map(encodeURIComponent).join("/");
const digest = async bytes => Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes)))
  .map(value => value.toString(16).padStart(2, "0")).join("");
const stable = value => {
  if (value === null || typeof value !== "object") return JSON.stringify(value);
  if (Array.isArray(value)) return `[${value.map(stable).join(",")}]`;
  return `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${stable(value[key])}`).join(",")}}`;
};
const parseJsonl = text => text.split(/\r?\n/).filter(line => line.trim()).map(line => JSON.parse(line));
const fetchBytes = async url => {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`${response.status} while loading ${url}`);
  return new Uint8Array(await response.arrayBuffer());
};
const decode = bytes => new TextDecoder().decode(bytes);
const resolveCanonicalUrl = value => {
  if (!value) return datasetBase + "annotations.jsonl";
  if (value.startsWith("local:")) {
    const path = value.slice("local:".length);
    return new URL(path, document.baseURI).href;
  }
  return value;
};

try {
  const manifestUrl = datasetBase + encodePath(manifestName);
  const canonicalUrl = resolveCanonicalUrl(vars.CANONICAL_ANNOTATIONS_URL);
  const [template, manifestBytes, canonicalBytes] = await Promise.all([
    fetch("app/static/component.html").then(response => {
      if (!response.ok) throw new Error(`${response.status} while loading the interface`);
      return response.text();
    }),
    fetchBytes(manifestUrl),
    fetchBytes(canonicalUrl),
  ]);
  const figures = parseJsonl(decode(manifestBytes));
  const records = parseJsonl(decode(canonicalBytes));
  for (const figure of figures) {
    figure.media_url = datasetBase + encodePath(figure.media_path);
  }
  const recordHashes = await Promise.all(records.map(async record => [
    `${record.dataset_id}\u001f${record.figure_id}`,
    await digest(new TextEncoder().encode(stable(record))),
  ]));
  root.innerHTML = template;
  globalThis.MAT_ELEMENT = root;
  globalThis.MAT_BOOTSTRAP = {
    mode: "hf-static",
    dataset: {
      id: datasetId,
      revision,
      manifest_sha256: await digest(manifestBytes),
    },
    canonical: {
      url: canonicalUrl,
      sha256: await digest(canonicalBytes),
      records,
      record_sha256: Object.fromEntries(recordHashes),
    },
    figures,
    github_repository_url: vars.GITHUB_REPOSITORY_URL || "",
  };
  await import("./app/static/component.js");
} catch (error) {
  root.innerHTML = `<main class="load-error"><h1>Map annotation tool</h1><p>Could not load the annotation data.</p><pre></pre></main>`;
  root.querySelector("pre").textContent = error.message;
}