@sjcrh/proteinpaint-server 2.135.1 → 2.135.2

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.135.1",
3
+ "version": "2.135.2",
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.121.0",
64
- "@sjcrh/proteinpaint-python": "2.135.0",
64
+ "@sjcrh/proteinpaint-python": "2.135.2-0",
65
65
  "@sjcrh/proteinpaint-r": "2.130.0",
66
- "@sjcrh/proteinpaint-rust": "2.135.0",
67
- "@sjcrh/proteinpaint-shared": "2.135.1",
68
- "@sjcrh/proteinpaint-types": "2.135.0",
66
+ "@sjcrh/proteinpaint-rust": "2.135.2-0",
67
+ "@sjcrh/proteinpaint-shared": "2.135.2-0",
68
+ "@sjcrh/proteinpaint-types": "2.135.2-0",
69
69
  "@types/express": "^5.0.0",
70
70
  "@types/express-session": "^1.18.1",
71
71
  "better-sqlite3": "^9.4.1",
@@ -1,9 +1,10 @@
1
1
  import { runGRIN2Payload } from "#types/checkers";
2
- import { stream_rust } from "@sjcrh/proteinpaint-rust";
2
+ import { run_rust } from "@sjcrh/proteinpaint-rust";
3
3
  import serverconfig from "#src/serverconfig.js";
4
4
  import path from "path";
5
5
  import { run_python } from "@sjcrh/proteinpaint-python";
6
6
  import { mayLog } from "#src/helpers.ts";
7
+ const MAX_RECORD = 1e5;
7
8
  const api = {
8
9
  endpoint: "gdc/runGRIN2",
9
10
  methods: {
@@ -43,12 +44,13 @@ async function runGrin2(genomes, req, res) {
43
44
  caseFiles: parsedRequest.caseFiles,
44
45
  mafOptions: parsedRequest.mafOptions,
45
46
  cnvOptions: parsedRequest.cnvOptions,
46
- chromosomes: []
47
+ chromosomes: [],
48
+ max_record: MAX_RECORD
47
49
  };
48
50
  const pyInput = {
49
51
  genedb: path.join(serverconfig.tpmasterdir, g.genedb.dbfile),
50
52
  chromosomelist: {},
51
- lesion: []
53
+ lesion: ""
52
54
  };
53
55
  for (const c in g.majorchr) {
54
56
  if (ds.queries.singleSampleMutation?.discoPlot?.skipChrM) {
@@ -58,63 +60,33 @@ async function runGrin2(genomes, req, res) {
58
60
  rustInput.chromosomes.push(c);
59
61
  pyInput.chromosomelist[c] = g.majorchr[c];
60
62
  }
61
- let rustOutput = "";
62
- let buffer = "";
63
63
  const downloadStartTime = Date.now();
64
- const streamResult = stream_rust("gdcGRIN2", JSON.stringify(rustInput), (errors) => {
65
- if (errors) {
66
- throw new Error(`Rust process failed: ${errors}`);
67
- }
68
- });
69
- if (!streamResult) {
70
- throw new Error("Failed to start Rust streaming process");
71
- }
72
- for await (const chunk of streamResult.rustStream) {
73
- const chunkStr = chunk.toString();
74
- rustOutput += chunkStr;
75
- buffer += chunkStr;
76
- const lines = buffer.split("\n");
77
- buffer = lines.pop() || "";
78
- for (const line of lines) {
79
- const trimmedLine = line.trim();
80
- if (trimmedLine) {
81
- try {
82
- const data = JSON.parse(trimmedLine);
83
- if (data.type === "summary") {
84
- mayLog(`[GRIN2] Download complete: ${data.successful_files}/${data.total_files} files successful`);
85
- if (data.failed_files > 0) {
86
- mayLog(`[GRIN2] ${data.failed_files} files failed`);
87
- }
88
- }
89
- } catch (_parseError) {
90
- }
91
- }
92
- }
93
- }
64
+ const rustOutput = await run_rust("gdcGRIN2", JSON.stringify(rustInput));
94
65
  mayLog("[GRIN2] Rust execution completed");
95
66
  const downloadTime = Date.now() - downloadStartTime;
96
67
  const downloadTimeToPrint = Math.round(downloadTime / 1e3);
97
- mayLog(`[GRIN2] Rust processing took ${downloadTimeToPrint}`);
98
- const rustResult = parseJsonlOutput(rustOutput);
99
- if (!rustResult) {
100
- throw new Error("Failed to process MAF files: No result from Rust");
68
+ mayLog(`[GRIN2] Rust processing took ${downloadTimeToPrint} seconds`);
69
+ const parsedRustResult = parseRustOutput(rustOutput);
70
+ if (!parsedRustResult) {
71
+ throw new Error("Failed to process files: No result from Rust");
101
72
  }
102
- const parsedRustResult = rustResult;
103
- if (parsedRustResult.successful_data && Array.isArray(parsedRustResult.successful_data)) {
104
- pyInput.lesion = parsedRustResult.successful_data.flat();
105
- mayLog(`[GRIN2] Extracted ${pyInput.lesion.length} records for python script`);
73
+ if (parsedRustResult.successful_data !== void 0 && parsedRustResult.successful_data !== null) {
74
+ pyInput.lesion = parsedRustResult.successful_data;
75
+ mayLog(`[GRIN2] Extracted ${parsedRustResult.successful_data.length.toLocaleString()} characters for python script`);
106
76
  mayLog(
107
- `[GRIN2] Success: ${parsedRustResult.summary.successful_files}, Failed: ${parsedRustResult.summary.failed_files}`
77
+ `[GRIN2] Success: ${parsedRustResult.summary.successful_files.toLocaleString()}, Failed: ${parsedRustResult.summary.failed_files.toLocaleString()}`
108
78
  );
109
79
  } else {
110
- throw "Unexpected Rust result format";
80
+ throw "No successful data returned from Rust processing";
111
81
  }
112
82
  const grin2AnalysisStart = Date.now();
113
- const pyResult = await run_python("gdcGRIN2.py", JSON.stringify(pyInput));
114
- mayLog(`[GRIN2] Python stderr: ${pyResult.stderr}`);
83
+ const pyResult = await run_python("grin2PpWrapper.py", JSON.stringify(pyInput));
84
+ if (pyResult.stderr?.trim()) {
85
+ mayLog(`[GRIN2] Python stderr: ${pyResult.stderr}`);
86
+ }
115
87
  const grin2AnalysisTime = Date.now() - grin2AnalysisStart;
116
88
  const grin2AnalysisTimeToPrint = Math.round(grin2AnalysisTime / 1e3);
117
- mayLog(`[GRIN2] Python processing took ${grin2AnalysisTimeToPrint}`);
89
+ mayLog(`[GRIN2] Python processing took ${grin2AnalysisTimeToPrint} seconds`);
118
90
  const resultData = JSON.parse(pyResult);
119
91
  const pngImg = resultData.png[0];
120
92
  const topGeneTable = resultData.topGeneTable || null;
@@ -131,88 +103,36 @@ async function runGrin2(genomes, req, res) {
131
103
  status: "success"
132
104
  });
133
105
  }
134
- function parseJsonlOutput(rustOutput) {
135
- const lines = rustOutput.trim().split("\n");
136
- const allSuccessfulData = [];
137
- let finalSummary = null;
138
- let processedFiles = 0;
139
- const MAX_RECORDS = 1e5;
140
- let totalRecordsProcessed = 0;
141
- let isCapReached = false;
142
- for (const line of lines) {
143
- const trimmedLine = line.trim();
144
- if (trimmedLine) {
145
- try {
146
- const data = JSON.parse(trimmedLine);
147
- if (data.type === "data") {
148
- if (isCapReached) {
149
- mayLog(`[GRIN2] Skipping file ${data.case_id} - record cap of ${MAX_RECORDS} already reached`);
150
- continue;
151
- }
152
- const remainingCapacity = MAX_RECORDS - totalRecordsProcessed;
153
- const incomingRecords = data.data.length;
154
- let recordsToProcess;
155
- let recordsProcessedThisFile;
156
- if (incomingRecords <= remainingCapacity) {
157
- recordsToProcess = data.data;
158
- recordsProcessedThisFile = incomingRecords;
159
- } else {
160
- recordsToProcess = data.data.slice(0, remainingCapacity);
161
- recordsProcessedThisFile = remainingCapacity;
162
- isCapReached = true;
163
- mayLog(
164
- `[GRIN2] Record cap reached! Processing only ${recordsProcessedThisFile} of ${incomingRecords} records from file ${data.case_id}`
165
- );
166
- }
167
- processedFiles++;
168
- allSuccessfulData.push(recordsToProcess);
169
- totalRecordsProcessed += recordsProcessedThisFile;
170
- mayLog(
171
- `[GRIN2] Processed file ${processedFiles}: ${data.case_id} (${data.data_type}) - ${recordsProcessedThisFile} records`
172
- );
173
- mayLog(`[GRIN2] Total records processed: ${totalRecordsProcessed}/${MAX_RECORDS}`);
174
- if (isCapReached) {
175
- mayLog(`[GRIN2] RECORD CAP REACHED: ${MAX_RECORDS} records processed. Subsequent files will be skipped.`);
176
- }
177
- } else if (data.type === "summary") {
178
- finalSummary = data;
179
- mayLog(`[GRIN2] Download complete: ${data.successful_files}/${data.total_files} files successful`);
180
- if (isCapReached) {
181
- mayLog(`[GRIN2] Processing stopped due to record cap of ${MAX_RECORDS}`);
182
- mayLog(`[GRIN2] Total records collected: ${totalRecordsProcessed}`);
183
- }
184
- if (data.failed_files > 0) {
185
- mayLog(`[GRIN2] ${data.failed_files} files failed`);
186
- }
187
- }
188
- } catch (parseError) {
189
- console.error("[GRIN2] JSONL parse error:", parseError);
190
- console.error("[GRIN2] Problematic line:", trimmedLine);
191
- }
106
+ function parseRustOutput(rustOutput) {
107
+ try {
108
+ const rustResult = JSON.parse(rustOutput);
109
+ if (!rustResult.grin2lesion || !rustResult.summary) {
110
+ throw new Error("Invalid Rust output: missing lesion data or summary");
192
111
  }
112
+ mayLog(`[GRIN2] Parsed Rust output successfully`);
113
+ return {
114
+ successful_data: rustResult.grin2lesion,
115
+ failed_files: rustResult.summary.errors || [],
116
+ summary: {
117
+ type: "summary",
118
+ total_files: rustResult.summary.total_files,
119
+ successful_files: rustResult.summary.successful_files,
120
+ failed_files: rustResult.summary.failed_files,
121
+ errors: rustResult.summary.errors || [],
122
+ filtered_records: rustResult.summary.filtered_records || 0,
123
+ filtered_maf_records: rustResult.summary.filtered_maf_records || 0,
124
+ filtered_cnv_records: rustResult.summary.filtered_cnv_records || 0,
125
+ included_maf_records: rustResult.summary.included_maf_records || 0,
126
+ included_cnv_records: rustResult.summary.included_cnv_records || 0,
127
+ filtered_records_by_case: rustResult.summary.filtered_records_by_case || {},
128
+ hyper_mutator_records: rustResult.summary.hyper_mutator_records || {},
129
+ excluded_by_max_record: rustResult.summary.excluded_by_max_record || {},
130
+ skippedChromosomes: rustResult.summary.skipped_chromosomes || {}
131
+ }
132
+ };
133
+ } catch (error) {
134
+ throw new Error(`Failed to parse Rust output: ${error instanceof Error ? error.message : "Unknown error"}`);
193
135
  }
194
- if (!finalSummary) {
195
- throw new Error("No summary found in Rust output");
196
- }
197
- return {
198
- successful_data: allSuccessfulData,
199
- failed_files: finalSummary.errors || [],
200
- summary: {
201
- type: "summary",
202
- total_files: finalSummary.total_files,
203
- successful_files: finalSummary.successful_files,
204
- failed_files: finalSummary.failed_files,
205
- errors: finalSummary.errors || [],
206
- filtered_records: finalSummary.filtered_records || 0,
207
- filtered_maf_records: finalSummary.filtered_maf_records || 0,
208
- filtered_cnv_records: finalSummary.filtered_cnv_records || 0,
209
- included_maf_records: finalSummary.included_maf_records || 0,
210
- included_cnv_records: finalSummary.included_cnv_records || 0,
211
- filtered_records_by_case: finalSummary.filtered_records_by_case || {},
212
- hyper_mutator_records: finalSummary.hyper_mutator_records || {},
213
- skippedChromosomes: finalSummary.skipped_chromosomes || {}
214
- }
215
- };
216
136
  }
217
137
  export {
218
138
  api
@@ -32,7 +32,7 @@ async function getScores(query, ds, genome) {
32
32
  const terms = [query.facilityTW];
33
33
  for (const term of query.scoreTerms) {
34
34
  terms.push(term.score);
35
- if (term.maxScore) {
35
+ if (term.maxScore?.term) {
36
36
  terms.push(term.maxScore);
37
37
  }
38
38
  }