@sjcrh/proteinpaint-server 2.147.0 → 2.147.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.147.0",
3
+ "version": "2.147.1",
4
4
  "type": "module",
5
5
  "description": "a genomics visualization tool for exploring a cohort's genotype and phenotype data",
6
6
  "main": "src/app.js",
@@ -64,8 +64,8 @@
64
64
  "@sjcrh/proteinpaint-python": "2.146.0",
65
65
  "@sjcrh/proteinpaint-r": "2.146.4-0",
66
66
  "@sjcrh/proteinpaint-rust": "2.146.4-1",
67
- "@sjcrh/proteinpaint-shared": "2.146.4-1",
68
- "@sjcrh/proteinpaint-types": "2.146.4-1",
67
+ "@sjcrh/proteinpaint-shared": "2.147.1",
68
+ "@sjcrh/proteinpaint-types": "2.147.1",
69
69
  "@types/express": "^5.0.0",
70
70
  "@types/express-session": "^1.18.1",
71
71
  "better-sqlite3": "^9.4.1",
@@ -1,6 +1,3 @@
1
- import path from "path";
2
- import fs from "fs";
3
- import serverconfig from "#src/serverconfig.js";
4
1
  import { aiProjectSelectedWSImagesResponsePayload } from "#types/checkers";
5
2
  import { getDbConnection } from "#src/aiHistoDBConnection.ts";
6
3
  const api = {
@@ -37,31 +34,12 @@ function init({ genomes }) {
37
34
  wsimage.uncertainty = ds.queries?.WSImages?.uncertainty;
38
35
  wsimage.activePatchColor = ds.queries?.WSImages?.activePatchColor;
39
36
  if (ds.queries.WSImages.getWSIPredictionPatches) {
40
- const predictionsFile = await ds.queries.WSImages.getWSIPredictionPatches(projectId, wsimageFilename);
41
- const mount = serverconfig.features?.tileserver?.mount;
42
- if (!mount) throw new Error("No mount available for TileServer");
43
- const predictionsFilePath = path.join(mount, ds.queries.WSImages.aiToolImageFolder, predictionsFile[0]);
44
- const predictionsData = JSON.parse(fs.readFileSync(predictionsFilePath, "utf8"));
45
- wsimage.predictions = predictionsData.features.map((d) => {
46
- const featClass = wsimage.classes?.find((f) => f.id == d.properties.class)?.label;
47
- return {
48
- zoomCoordinates: d.properties.zoomCoordinates,
49
- uncertainty: d.properties.uncertainty,
50
- class: featClass
51
- };
52
- });
37
+ const predictions = await ds.queries.WSImages.getWSIPredictionPatches(projectId, wsimageFilename);
38
+ wsimage.predictions = predictions;
53
39
  }
54
40
  wsimages.push(wsimage);
55
41
  }
56
42
  }
57
- if (ds.queries.WSImages.getWSIPredictionOverlay) {
58
- for (const wsimage of wsimages) {
59
- const predictionOverlay = await ds.queries.WSImages.getWSIPredictionOverlay(wsimage.filename);
60
- if (predictionOverlay) {
61
- wsimage.predictionLayers = [predictionOverlay];
62
- }
63
- }
64
- }
65
43
  res.send({ wsimages });
66
44
  } catch (e) {
67
45
  console.log(e);
@@ -0,0 +1,61 @@
1
+ import { aiProjectTrainModelPayload } from "#types/checkers";
2
+ import { TileServerSessionsHandler } from "#src/wsisessions/TileServerSessionsHandler.ts";
3
+ import SessionManager from "#src/wsisessions/SessionManager.ts";
4
+ const api = {
5
+ endpoint: "aiProjectTrainModel",
6
+ methods: {
7
+ get: {
8
+ ...aiProjectTrainModelPayload,
9
+ init
10
+ },
11
+ post: {
12
+ ...aiProjectTrainModelPayload,
13
+ init
14
+ }
15
+ }
16
+ };
17
+ function init({ genomes }) {
18
+ return async function(req, res) {
19
+ try {
20
+ const query = req.query;
21
+ console.log(query);
22
+ const g = genomes[query.genome];
23
+ if (!g) throw "invalid genome name";
24
+ const ds = g.datasets[query.dslabel];
25
+ if (!ds) throw "invalid dataset name";
26
+ if (typeof ds.queries.WSImages.retrainModel == "function") {
27
+ await ds.queries.WSImages.retrainModel(query.projectId);
28
+ try {
29
+ const handler = new TileServerSessionsHandler();
30
+ const sessionMgr = SessionManager.getInstance();
31
+ const keySessions = await sessionMgr.getAllKeyValues();
32
+ const sessions = keySessions.map((kv) => kv?.sessionData).filter(Boolean);
33
+ if (sessions && sessions.length) {
34
+ await handler.resetSessions(sessions);
35
+ await Promise.all(keySessions.map((kv) => sessionMgr.deleteSession(kv.key)));
36
+ }
37
+ } catch (err) {
38
+ console.warn("TileServerSessionsHandler error:", err);
39
+ }
40
+ } else {
41
+ res.status(500).send({
42
+ status: "error",
43
+ error: "No retraining script defined"
44
+ });
45
+ }
46
+ res.status(200).send({
47
+ status: "ok",
48
+ message: `Retraining model completed`
49
+ });
50
+ } catch (e) {
51
+ console.warn(e);
52
+ res.status(500).send({
53
+ status: "error",
54
+ error: e.message || e
55
+ });
56
+ }
57
+ };
58
+ }
59
+ export {
60
+ api
61
+ };
@@ -2,6 +2,7 @@ import { termdbCohortSummaryPayload } from "#types/checkers";
2
2
  import { get_ds_tdb } from "#src/termdb.js";
3
3
  import { mayCopyFromCookie } from "#src/utils.js";
4
4
  import { get_samples } from "#src/termdb.sql.js";
5
+ import { authApi } from "#src/auth.js";
5
6
  const api = {
6
7
  endpoint: "termdb/cohort/summary",
7
8
  methods: {
@@ -19,6 +20,7 @@ function init({ genomes }) {
19
20
  const genome = genomes[q.genome];
20
21
  if (!genome) throw "invalid genome";
21
22
  const [ds] = get_ds_tdb(genome, q);
23
+ authApi.mayAdjustFilter(req.query, ds, []);
22
24
  let count;
23
25
  if (q.filter?.lst?.length) {
24
26
  const samples = await get_samples(q, ds);
@@ -55,7 +55,8 @@ function getList(samplesPerFilter, filtersData, tw, showAll) {
55
55
  const sampleValues = Array.from(new Set(annotations));
56
56
  const filteredValues = [];
57
57
  for (const value of values) {
58
- const label = value.label.replace(/["']/g, "");
58
+ let label = value.label.replace(/["']/g, "");
59
+ if (label.length > 50) label = label.slice(0, 47) + "...";
59
60
  const disabled = !sampleValues.includes(value.key || value.label);
60
61
  if (!showAll && disabled) continue;
61
62
  filteredValues.push({ value: value.key || value.label, label, disabled });
@@ -1,5 +1,5 @@
1
1
  import { ProfileFormScoresPayload } from "#types/checkers";
2
- import { getData } from "../src/termdb.matrix.js";
2
+ import { getScoresData } from "./termdb.profileScores.js";
3
3
  const api = {
4
4
  endpoint: "termdb/profileFormScores",
5
5
  methods: {
@@ -28,56 +28,24 @@ function init({ genomes }) {
28
28
  };
29
29
  }
30
30
  async function getScoresDict(query, ds) {
31
- if (!query.filterByUserSites) query.__protected__.ignoredTermIds.push(query.facilityTW.term.id);
32
31
  const terms = [...query.scoreTerms, query.facilityTW];
33
32
  if (query.scScoreTerms) terms.push(...query.scScoreTerms);
34
- const data = await getData(
35
- {
36
- terms,
37
- filter: query.site || !query.isAggregate ? void 0 : query.filter,
38
- //if isRadarFacility and site is specified, do not apply the filter
39
- __protected__: query.__protected__
40
- },
41
- ds
42
- );
43
- const lst = Object.values(data.samples);
44
- let sites = lst.map((s) => {
45
- return { label: data.refs.bySampleId[s.sample].label, value: s.sample };
46
- });
47
- sites = lst.map((s) => {
48
- return { label: data.refs.bySampleId[s.sample].label, value: s.sample };
49
- });
50
- if (query.userSites) {
51
- sites = sites.filter((s) => query.userSites.includes(s.label));
52
- if (lst.length == 1 && !sites.length) {
53
- const siteId = lst[0].sample;
54
- const site = data.refs.bySampleId[siteId].label;
55
- const hospital2 = query.facilityTW.term.values[site].label;
56
- throw `The access to the hospital ${hospital2} is denied`;
57
- }
58
- }
59
- let sitesSelected = [];
60
- if (query.site) sitesSelected = [query.site];
61
- else if (!query.isAggregate) sitesSelected = [sites[0].value];
62
- else sitesSelected = query.sites;
63
- const sampleData = sitesSelected?.length == 1 ? data.samples[sitesSelected[0]] : null;
64
- let samples = sampleData ? [sampleData] : Object.values(data.samples);
65
- if (sitesSelected?.length > 0) samples = samples.filter((s) => sitesSelected.includes(s.sample));
33
+ const data = await getScoresData(query, ds, terms);
66
34
  const term2Score = {};
67
35
  for (const d of query.scoreTerms) {
68
36
  const getDictFunc = (sample) => getDict(d.$id, sample);
69
- const percents = getPercentsDict(getDictFunc, samples);
37
+ const percents = getPercentsDict(getDictFunc, data.samples);
70
38
  term2Score[d.term.id] = percents;
71
39
  }
72
40
  if (query.scScoreTerms)
73
41
  for (const d of query.scScoreTerms) {
74
- const percents = getSCPercentsDict(d, samples);
42
+ const percents = getSCPercentsDict(d, data.samples);
75
43
  term2Score[d.term.id] = percents;
76
44
  }
77
- const facilityValue = sampleData?.[query.facilityTW.$id];
45
+ const facilityValue = data.sampleData?.[query.facilityTW.$id];
78
46
  const termValue = query.facilityTW.term.values[facilityValue?.value];
79
47
  const hospital = termValue?.label || termValue?.key;
80
- return { term2Score, sites, hospital, n: sampleData ? 1 : samples.length };
48
+ return { term2Score, sites: data.sites, hospital, n: data.sampleData ? 1 : data.samples.length };
81
49
  }
82
50
  function getDict(key, sample) {
83
51
  if (!sample[key]) return null;
@@ -27,52 +27,61 @@ function init({ genomes }) {
27
27
  }
28
28
  };
29
29
  }
30
- async function getScores(query, ds) {
30
+ async function getScoresData(query, ds, terms) {
31
31
  if (!query.filterByUserSites) query.__protected__.ignoredTermIds.push(query.facilityTW.term.id);
32
- const terms = [query.facilityTW];
33
- for (const term of query.scoreTerms) {
34
- terms.push(term.score);
35
- if (term.maxScore?.term) {
36
- terms.push(term.maxScore);
37
- }
38
- }
32
+ const { clientAuthResult, activeCohort } = query.__protected__;
33
+ const userSites = clientAuthResult[activeCohort].sites;
39
34
  const data = await getData(
40
35
  {
41
36
  terms,
42
- filter: query.site || !query.isAggregate ? void 0 : query.filter,
43
- //if site is specified, do not apply the filter that is for the aggregation
37
+ filter: query.filter,
44
38
  __protected__: query.__protected__
45
39
  },
46
40
  ds
47
41
  );
42
+ if (data.error) throw data.error;
48
43
  const lst = Object.values(data.samples);
49
44
  let sites = lst.map((s) => {
50
- return { label: data.refs.bySampleId[s.sample].label, value: s.sample };
45
+ let label = query.facilityTW.term.values[s[query.facilityTW.$id].value]?.label || s[query.facilityTW.$id].value;
46
+ if (label.length > 50) label = label.slice(0, 47) + "...";
47
+ return {
48
+ value: s[query.facilityTW.$id].value,
49
+ label
50
+ };
51
+ });
52
+ if (userSites) {
53
+ sites = sites.filter((s) => userSites.includes(s.value));
54
+ }
55
+ sites.sort((a, b) => {
56
+ return a.label.localeCompare(b.label);
51
57
  });
52
- if (query.userSites) {
53
- sites = sites.filter((s) => query.userSites.includes(s.label));
54
- if (lst.length == 1 && !sites.length) {
55
- const siteId = lst[0].sample;
56
- const site = data.refs.bySampleId[siteId].label;
57
- const hospital2 = query.facilityTW.term.values[site].label;
58
- throw `The access to the hospital ${hospital2} is denied`;
58
+ const samples = Object.values(data.samples);
59
+ let sampleData, site;
60
+ if ("facilitySite" in query) {
61
+ const facilitySite = query.facilitySite || sites[0].value;
62
+ const index = lst.findIndex((s) => s[query.facilityTW.$id].value == facilitySite);
63
+ sampleData = lst[index];
64
+ site = sites.find((s) => s.value == facilitySite);
65
+ } else if (sites.length == 1) {
66
+ sampleData = data.samples[sites[0].value];
67
+ site = sites[0];
68
+ }
69
+ return { samples, sampleData, sites, site };
70
+ }
71
+ async function getScores(query, ds) {
72
+ const terms = [query.facilityTW];
73
+ for (const term of query.scoreTerms) {
74
+ terms.push(term.score);
75
+ if (term.maxScore?.term) {
76
+ terms.push(term.maxScore);
59
77
  }
60
78
  }
61
- let sitesSelected = [];
62
- if (query.site) sitesSelected = [query.site];
63
- else if (!query.isAggregate) sitesSelected = [sites[0].value];
64
- else sitesSelected = query.sites;
65
- const sampleData = sitesSelected?.length == 1 ? data.samples[sitesSelected[0]] : null;
66
- let samples = Object.values(data.samples);
67
- if (sitesSelected?.length > 0) samples = samples.filter((s) => sitesSelected.includes(s.sample));
79
+ const data = await getScoresData(query, ds, terms);
68
80
  const term2Score = {};
69
81
  for (const d of query.scoreTerms) {
70
- term2Score[d.score.term.id] = getPercentage(d, samples, sampleData);
82
+ term2Score[d.score.term.id] = getPercentage(d, data.samples, data.sampleData);
71
83
  }
72
- const facilityValue = sampleData?.[query.facilityTW.$id];
73
- const termValue = query.facilityTW.term.values[facilityValue?.value];
74
- const hospital = termValue?.label || termValue?.key;
75
- return { term2Score, sites, hospital, n: sampleData ? 1 : samples.length };
84
+ return { term2Score, sites: data.sites, site: data.site, n: data.sampleData ? 1 : data.samples.length };
76
85
  }
77
86
  function getPercentage(d, samples, sampleData) {
78
87
  if (!d) return null;
@@ -91,5 +100,6 @@ function getPercentage(d, samples, sampleData) {
91
100
  }
92
101
  }
93
102
  export {
94
- api
103
+ api,
104
+ getScoresData
95
105
  };
@@ -30,7 +30,7 @@ function init({ genomes }) {
30
30
  if (!g) throw "invalid genome name";
31
31
  const ds = g.datasets?.[q.dslabel];
32
32
  if (!ds) throw "invalid ds";
33
- data = await trigger_getViolinPlotData(q, ds);
33
+ data = await getViolin(q, ds);
34
34
  } catch (e) {
35
35
  data = { error: e?.message || e };
36
36
  if (e instanceof Error && e.stack) console.log(e);
@@ -38,7 +38,7 @@ function init({ genomes }) {
38
38
  res.send(data);
39
39
  };
40
40
  }
41
- async function trigger_getViolinPlotData(q, ds) {
41
+ async function getViolin(q, ds) {
42
42
  if (typeof q.tw?.term != "object" || typeof q.tw?.q != "object") throw "q.tw not of {term,q}";
43
43
  const term = q.tw.term;
44
44
  if (!q.tw.q.mode) q.tw.q.mode = "continuous";
@@ -175,7 +175,7 @@ async function createCanvasImg(q, result, ds) {
175
175
  if (q.radius <= 0) throw "q.radius is not a number";
176
176
  else q.radius = +q.radius;
177
177
  if (!q.strokeWidth) q.strokeWidth = 0.2;
178
- const refSize = q.radius * 4;
178
+ const isH = q.orientation == "horizontal";
179
179
  for (const k of Object.keys(result.charts)) {
180
180
  const chart = result.charts[k];
181
181
  const plot2Values = {};
@@ -184,46 +184,44 @@ async function createCanvasImg(q, result, ds) {
184
184
  let axisScale;
185
185
  const useLog = q.unit == "log";
186
186
  if (useLog) {
187
- axisScale = scaleLog().base(ds.cohort.termdb.logscaleBase2 ? 2 : 10).domain([result.min, result.max]).range(q.orientation === "horizontal" ? [0, q.svgw] : [q.svgw, 0]);
187
+ axisScale = scaleLog().base(ds.cohort.termdb.logscaleBase2 ? 2 : 10).domain([result.min, result.max]).range(isH ? [0, q.svgw] : [q.svgw, 0]);
188
188
  } else {
189
- axisScale = scaleLinear().domain([result.min, result.max]).range(q.orientation === "horizontal" ? [0, q.svgw] : [q.svgw, 0]);
189
+ axisScale = scaleLinear().domain([result.min, result.max]).range(isH ? [0, q.svgw] : [q.svgw, 0]);
190
190
  }
191
- const [width, height] = q.orientation == "horizontal" ? [q.svgw * q.devicePixelRatio, refSize * q.devicePixelRatio] : [refSize * q.devicePixelRatio, q.svgw * q.devicePixelRatio];
192
- const scaledRadius = q.radius / q.devicePixelRatio;
193
- const arcEndAngle = scaledRadius * Math.PI;
191
+ const [width, height] = isH ? [q.svgw * q.devicePixelRatio, q.radius * q.devicePixelRatio] : [q.radius * q.devicePixelRatio, q.svgw * q.devicePixelRatio];
194
192
  for (const plot of chart.plots) {
195
193
  plot.density = densities[plot.label];
196
- const noDensityRendered = plot.density.densityMax == 0;
197
194
  const canvas = createCanvas(width, height);
198
195
  const ctx = canvas.getContext("2d");
199
- const symbolOpacity = noDensityRendered ? 1 : 0.6;
200
- ctx.strokeStyle = `rgba(0,0,0,${symbolOpacity})`;
201
- ctx.lineWidth = q.strokeWidth / q.devicePixelRatio;
202
- ctx.globalAlpha = symbolOpacity;
203
- ctx.fillStyle = "#ffe6e6";
204
- if (q.devicePixelRatio != 1) {
205
- ctx.scale(q.devicePixelRatio, q.devicePixelRatio);
206
- }
207
- if (q.datasymbol === "rug")
196
+ if (q.devicePixelRatio != 1) ctx.scale(q.devicePixelRatio, q.devicePixelRatio);
197
+ ctx.strokeStyle = "black";
198
+ ctx.lineWidth = 1;
199
+ if (q.datasymbol === "rug") {
200
+ ctx.globalAlpha = 0.8;
208
201
  plot.values.forEach((i) => {
202
+ const s = axisScale(i);
209
203
  ctx.beginPath();
210
- if (q.orientation == "horizontal") {
211
- ctx.moveTo(+axisScale(i), 0);
212
- ctx.lineTo(+axisScale(i), scaledRadius * 2);
204
+ if (isH) {
205
+ ctx.moveTo(s, 0);
206
+ ctx.lineTo(s, q.radius);
213
207
  } else {
214
- ctx.moveTo(0, +axisScale(i));
215
- ctx.lineTo(scaledRadius * 2, +axisScale(i));
208
+ ctx.moveTo(0, s);
209
+ ctx.lineTo(q.radius, s);
216
210
  }
217
211
  ctx.stroke();
218
212
  });
219
- else if (q.datasymbol === "bean")
213
+ } else if (q.datasymbol === "bean") {
214
+ ctx.globalAlpha = 0.6;
215
+ ctx.fillStyle = "#ffe6e6";
220
216
  plot.values.forEach((i) => {
217
+ const s = axisScale(i);
221
218
  ctx.beginPath();
222
- if (q.orientation === "horizontal") ctx.arc(+axisScale(i), q.radius, scaledRadius, 0, arcEndAngle);
223
- else ctx.arc(q.radius, +axisScale(i), scaledRadius, 0, arcEndAngle);
219
+ if (isH) ctx.arc(s, q.radius / 2, q.radius / 2, 0, 2 * Math.PI);
220
+ else ctx.arc(q.radius / 2, s, q.radius / 2, 0, 2 * Math.PI);
224
221
  ctx.fill();
225
222
  ctx.stroke();
226
223
  });
224
+ }
227
225
  plot.src = canvas.toDataURL();
228
226
  plot.summaryStats = getDescrStats(plot.values);
229
227
  }
@@ -264,6 +262,5 @@ export {
264
262
  getDensities,
265
263
  getDensity,
266
264
  getWilcoxonData,
267
- sortPlot2Values,
268
- trigger_getViolinPlotData
265
+ sortPlot2Values
269
266
  };
@@ -40,7 +40,7 @@ function init({ genomes }) {
40
40
  const setCookie = promisify(cookieJar.setCookie.bind(cookieJar));
41
41
  const getCookieString = promisify(cookieJar.getCookieString.bind(cookieJar));
42
42
  const wsiImagePath = await getWSImagePath(ds, wSImagesRequest);
43
- const session = await getSessionId(ds, cookieJar, getCookieString, setCookie, wsiImagePath);
43
+ const session = await getSessionId(ds, cookieJar, getCookieString, setCookie, wsiImagePath, aiProjectId);
44
44
  const getWsiImageResponse = await getWsiImageDimensions(
45
45
  session.imageSessionId,
46
46
  getCookieString,
@@ -74,7 +74,7 @@ async function getWSImagePath(ds, wSImagesRequest) {
74
74
  return path.join(`${mount}/${ds.queries.WSImages.aiToolImageFolder}/`, wSImagesRequest.wsimage);
75
75
  }
76
76
  }
77
- async function getSessionId(ds, cookieJar, getCookieString, setCookie, wsimage) {
77
+ async function getSessionId(ds, cookieJar, getCookieString, setCookie, wsimage, projectId) {
78
78
  const sessionManager = SessionManager.getInstance();
79
79
  const invalidateResult = await sessionManager.syncAndInvalidateSessions(wsimage);
80
80
  if (!invalidateResult) throw new Error("Session invalidation failed");
@@ -102,55 +102,39 @@ async function getSessionId(ds, cookieJar, getCookieString, setCookie, wsimage)
102
102
  },
103
103
  hooks: getHooks(cookieJar, getCookieString, setCookie)
104
104
  });
105
- if (ds.queries.WSImages.getWSIPredictionOverlay) {
106
- const predictionOverlay = await ds.queries.WSImages.getWSIPredictionOverlay(wsimage);
107
- if (predictionOverlay) {
105
+ if (ds.queries.WSImages.getPredictionLayers) {
106
+ const predictionLayers = await ds.queries.WSImages.getPredictionLayers(projectId, wsimage);
107
+ if (predictionLayers) {
108
108
  const mount = serverconfig.features?.tileserver?.mount;
109
- const overlayFilePath = path.join(`${mount}/${ds.queries.WSImages.aiToolImageFolder}/`, predictionOverlay);
110
- const annotationsData = qs.stringify({
111
- overlay_path: overlayFilePath
112
- });
113
- const layerNumber = await ky.put(`${tileServer.url}/tileserver/overlay`, {
114
- body: annotationsData,
115
- timeout: 5e4,
116
- headers: {
117
- "Content-Type": "application/x-www-form-urlencoded",
118
- Cookie: `session_id=${sessionId}`
119
- },
120
- hooks: getHooks(cookieJar, getCookieString, setCookie)
121
- }).json();
122
- const overlay = {
123
- layerNumber,
124
- predictionOverlayType: "Prediction"
109
+ const resolveFilename = (key) => {
110
+ if (!predictionLayers) return void 0;
111
+ if (predictionLayers instanceof Map) return predictionLayers.get(key) ?? void 0;
112
+ return predictionLayers[key] ?? void 0;
125
113
  };
126
- overlays.push(overlay);
127
- }
128
- }
129
- if (ds.queries.WSImages.getWSIUncertaintyOverlay) {
130
- const uncertaintyOverlay = await ds.queries.WSImages.getWSIUncertaintyOverlay(wsimage);
131
- if (uncertaintyOverlay) {
132
- const mount = serverconfig.features?.tileserver?.mount;
133
- const uncertaintyOverlayFilePath = path.join(
134
- `${mount}/${ds.queries.WSImages.aiToolImageFolder}/`,
135
- uncertaintyOverlay
136
- );
137
- const uncertaintyData = qs.stringify({
138
- overlay_path: uncertaintyOverlayFilePath
139
- });
140
- const layerNumber = await ky.put(`${tileServer.url}/tileserver/overlay`, {
141
- body: uncertaintyData,
142
- timeout: 5e4,
143
- headers: {
144
- "Content-Type": "application/x-www-form-urlencoded",
145
- Cookie: `session_id=${sessionId}`
146
- },
147
- hooks: getHooks(cookieJar, getCookieString, setCookie)
148
- }).json();
149
- const overlay = {
150
- layerNumber,
151
- predictionOverlayType: "Uncertainty"
114
+ const pushOverlayForKey = async (key, predictionOverlayType) => {
115
+ const filename = resolveFilename(key);
116
+ if (!filename) return;
117
+ const overlayFilePath = path.join(`${mount}/${ds.queries.WSImages.aiToolImageFolder}/`, filename);
118
+ const annotationsData = qs.stringify({
119
+ overlay_path: overlayFilePath
120
+ });
121
+ const layerNumber = await ky.put(`${tileServer.url}/tileserver/overlay`, {
122
+ body: annotationsData,
123
+ timeout: 5e4,
124
+ headers: {
125
+ "Content-Type": "application/x-www-form-urlencoded",
126
+ Cookie: `session_id=${sessionId}`
127
+ },
128
+ hooks: getHooks(cookieJar, getCookieString, setCookie)
129
+ }).json();
130
+ const overlay = {
131
+ layerNumber,
132
+ predictionOverlayType
133
+ };
134
+ overlays.push(overlay);
152
135
  };
153
- overlays.push(overlay);
136
+ await pushOverlayForKey("Prediction", "Prediction");
137
+ await pushOverlayForKey("Uncertainty", "Uncertainty");
154
138
  }
155
139
  }
156
140
  const sessionData = await sessionManager.setSession(wsimage, sessionId, tileServer, overlays);