@sjcrh/proteinpaint-server 2.145.2 → 2.146.0

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.145.2",
3
+ "version": "2.146.0",
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",
@@ -61,11 +61,11 @@
61
61
  },
62
62
  "dependencies": {
63
63
  "@sjcrh/augen": "2.143.0",
64
- "@sjcrh/proteinpaint-python": "2.144.0",
64
+ "@sjcrh/proteinpaint-python": "2.146.0",
65
65
  "@sjcrh/proteinpaint-r": "2.145.1-0",
66
- "@sjcrh/proteinpaint-rust": "2.145.2",
66
+ "@sjcrh/proteinpaint-rust": "2.146.0",
67
67
  "@sjcrh/proteinpaint-shared": "2.145.2",
68
- "@sjcrh/proteinpaint-types": "2.145.2",
68
+ "@sjcrh/proteinpaint-types": "2.146.0",
69
69
  "@types/express": "^5.0.0",
70
70
  "@types/express-session": "^1.18.1",
71
71
  "better-sqlite3": "^9.4.1",
@@ -82,9 +82,7 @@
82
82
  "got": "^14.2.0",
83
83
  "image-size": "^0.5.5",
84
84
  "jsonwebtoken": "^9.0.0",
85
- "jstat": "^1.9.3",
86
85
  "ky": "^1.2.1",
87
- "lazy": "^1.0.11",
88
86
  "micromatch": "^4.0.5",
89
87
  "minimatch": "^10.0.1",
90
88
  "node-fetch": "^2.6.1",
@@ -51,9 +51,6 @@ function init({ genomes }) {
51
51
  };
52
52
  });
53
53
  }
54
- if (ds.queries.WSImages.makeGeoJson) {
55
- await ds.queries.WSImages.makeGeoJson(projectId, wsimageFilename);
56
- }
57
54
  wsimages.push(wsimage);
58
55
  }
59
56
  }
@@ -0,0 +1,71 @@
1
+ import { ChatPayload } from "#types/checkers";
2
+ import { run_rust } from "@sjcrh/proteinpaint-rust";
3
+ import serverconfig from "../src/serverconfig.js";
4
+ import { mayLog } from "#src/helpers.ts";
5
+ const api = {
6
+ endpoint: "termdb/chat",
7
+ methods: {
8
+ get: {
9
+ ...ChatPayload,
10
+ init
11
+ },
12
+ post: {
13
+ ...ChatPayload,
14
+ init
15
+ }
16
+ }
17
+ };
18
+ function init({ genomes }) {
19
+ return async (req, res) => {
20
+ const q = req.query;
21
+ try {
22
+ const g = genomes[q.genome];
23
+ if (!g) throw "invalid genome";
24
+ const ds = g.datasets?.[q.dslabel];
25
+ if (!ds) throw "invalid dslabel";
26
+ let apilink;
27
+ let comp_model_name;
28
+ let embedding_model_name;
29
+ if (serverconfig.llm_backend == "SJ") {
30
+ apilink = serverconfig.sj_apilink;
31
+ comp_model_name = serverconfig.sj_comp_model_name;
32
+ embedding_model_name = serverconfig.sj_embedding_model_name;
33
+ } else if (serverconfig.llm_backend == "ollama") {
34
+ apilink = serverconfig.ollama_apilink;
35
+ comp_model_name = serverconfig.ollama_comp_model_name;
36
+ embedding_model_name = serverconfig.ollama_embedding_model_name;
37
+ } else {
38
+ throw "llm_backend either needs to be 'SJ' or 'ollama'";
39
+ }
40
+ const chatbot_input = {
41
+ // Just hardcoding variables here, these will later be defined in more appropriate places
42
+ user_input: q.prompt,
43
+ apilink,
44
+ dataset_db: serverconfig.tpmasterdir + "/" + ds.cohort.db.file,
45
+ comp_model_name,
46
+ embedding_model_name,
47
+ llm_backend_name: serverconfig.llm_backend
48
+ // The type of backend (engine) used for running the embedding and completion model. Currently "SJ" and "Ollama" are supported
49
+ };
50
+ const time1 = (/* @__PURE__ */ new Date()).valueOf();
51
+ const ai_output_data = await run_rust("aichatbot", JSON.stringify(chatbot_input));
52
+ const time2 = (/* @__PURE__ */ new Date()).valueOf();
53
+ mayLog("Time taken to run rust AI chatbot:", time2 - time1, "ms");
54
+ let ai_output_json = "";
55
+ for (const line of ai_output_data.split("\n")) {
56
+ if (line.startsWith("final_output:") == true) {
57
+ ai_output_json = JSON.parse(line.replace("final_output:", ""));
58
+ } else {
59
+ mayLog(line);
60
+ }
61
+ }
62
+ res.send(ai_output_json);
63
+ } catch (e) {
64
+ if (e.stack) console.log(e.stack);
65
+ res.send({ error: e?.message || e });
66
+ }
67
+ };
68
+ }
69
+ export {
70
+ api
71
+ };
@@ -1,6 +1,7 @@
1
1
  import { termdbCohortSummaryPayload } from "#types/checkers";
2
2
  import { get_ds_tdb } from "#src/termdb.js";
3
3
  import { mayCopyFromCookie } from "#src/utils.js";
4
+ import { get_samples } from "#src/termdb.sql.js";
4
5
  const api = {
5
6
  endpoint: "termdb/cohort/summary",
6
7
  methods: {
@@ -18,7 +19,11 @@ function init({ genomes }) {
18
19
  const genome = genomes[q.genome];
19
20
  if (!genome) throw "invalid genome";
20
21
  const [ds] = get_ds_tdb(genome, q);
21
- const count = ds.cohort.termdb.q?.getCohortSampleCount?.(q.cohort) || 1;
22
+ let count;
23
+ if (ds.cohort.termdb.getAdditionalFilter) {
24
+ const samples = await get_samples(q, ds);
25
+ count = samples.length;
26
+ } else count = ds.cohort.termdb.q?.getCohortSampleCount?.(q.cohort) || 1;
22
27
  res.send({ count });
23
28
  } catch (e) {
24
29
  res.send({ error: e.message || e });
@@ -134,15 +134,9 @@ function addNonDictionaryQueries(c, ds, genome) {
134
134
  };
135
135
  if (q.snvindel.byisoform?.processTwsInOneQuery) q2.snvindel.byisoform = { processTwsInOneQuery: true };
136
136
  }
137
- if (q.trackLst) {
138
- q2.trackLst = q.trackLst;
139
- }
140
137
  if (q.svfusion) {
141
138
  q2.svfusion = {};
142
139
  }
143
- if (q.ld) {
144
- q2.ld = JSON.parse(JSON.stringify(q.ld));
145
- }
146
140
  if (q.cnv) {
147
141
  q2.cnv = {};
148
142
  for (const k of [
@@ -177,6 +171,15 @@ function addNonDictionaryQueries(c, ds, genome) {
177
171
  if (q.geneExpression) {
178
172
  q2.geneExpression = { unit: q.geneExpression.unit };
179
173
  }
174
+ if (q.ld) {
175
+ q2.ld = structuredClone(q.ld);
176
+ }
177
+ if (q.trackLst) {
178
+ q2.trackLst = q.trackLst;
179
+ }
180
+ if (q.chat) {
181
+ q2.chat = {};
182
+ }
180
183
  if (q.NIdata && serverconfig.features.showBrainImaging) {
181
184
  q2.NIdata = {};
182
185
  for (const k in q.NIdata) {
@@ -56,6 +56,10 @@ async function trigger_getViolinPlotData(q, ds) {
56
56
  },
57
57
  ds
58
58
  );
59
+ const samples = Object.values(data.samples);
60
+ let values = samples.map((s) => s?.[q.tw.$id]?.value).filter((v) => typeof v === "number");
61
+ if (q.unit == "log") values = values.filter((v) => v > 0);
62
+ const descrStats = summaryStats(values).values;
59
63
  const sampleType = `All ${data.sampleType?.plural_name || "samples"}`;
60
64
  if (data.error) throw data.error;
61
65
  if (q.overlayTw && data.refs.byTermId[q.overlayTw.$id]) {
@@ -71,6 +75,7 @@ async function trigger_getViolinPlotData(q, ds) {
71
75
  const result = setResponse(valuesObject, data, q);
72
76
  if (q.overlayTw) await getWilcoxonData(result);
73
77
  await createCanvasImg(q, result, ds);
78
+ result["descrStats"] = descrStats;
74
79
  return result;
75
80
  }
76
81
  async function getWilcoxonData(result) {
@@ -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, aiProjectId);
43
+ const session = await getSessionId(ds, cookieJar, getCookieString, setCookie, wsiImagePath);
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, aiProjectId) {
77
+ async function getSessionId(ds, cookieJar, getCookieString, setCookie, wsimage) {
78
78
  const sessionManager = SessionManager.getInstance();
79
79
  const invalidateResult = await sessionManager.syncAndInvalidateSessions(wsimage);
80
80
  if (!invalidateResult) throw new Error("Session invalidation failed");
@@ -154,44 +154,6 @@ async function getSessionId(ds, cookieJar, getCookieString, setCookie, wsimage,
154
154
  }
155
155
  }
156
156
  const sessionData = await sessionManager.setSession(wsimage, sessionId, tileServer, overlays);
157
- if (ds.queries.WSImages.getWSIPredictionPatches) {
158
- const predictionPatches = await ds.queries.WSImages.getWSIPredictionPatches(aiProjectId, wsimage);
159
- if (!predictionPatches) throw new Error("No prediction files found");
160
- const mount = serverconfig.features?.tileserver?.mount;
161
- if (!mount) throw new Error("No mount available for TileServer");
162
- if (predictionPatches.length > 0) {
163
- for (const predictionPatch of predictionPatches) {
164
- const predictionFilePath = path.join(`${mount}/${ds.queries.WSImages.aiToolImageFolder}/`, predictionPatch);
165
- const predictionsData = qs.stringify({
166
- overlay_path: predictionFilePath
167
- });
168
- await ky.put(`${tileServer.url}/tileserver/overlay`, {
169
- body: predictionsData,
170
- timeout: 5e4,
171
- headers: {
172
- "Content-Type": "application/x-www-form-urlencoded",
173
- Cookie: `session_id=${sessionId}`
174
- },
175
- hooks: getHooks(cookieJar, getCookieString, setCookie)
176
- });
177
- }
178
- const cmapData = qs.stringify({
179
- cmap: JSON.stringify({
180
- keys: ["prediction", "annotation"],
181
- values: [ds.queries.WSImages.predictionColor, ds.queries.WSImages.annotationsColor]
182
- })
183
- });
184
- await ky.put(`${tileServer.url}/tileserver/cmap`, {
185
- body: cmapData,
186
- timeout: 5e4,
187
- headers: {
188
- "Content-Type": "application/x-www-form-urlencoded",
189
- Cookie: `session_id=${sessionId}`
190
- },
191
- hooks: getHooks(cookieJar, getCookieString, setCookie)
192
- });
193
- }
194
- }
195
157
  return sessionData;
196
158
  }
197
159
  async function getWsiImageDimensions(sessionId, getCookieString, wsimage) {