Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNOMED Hydrating, Filtering, Special MR Generation #1648

Draft
wants to merge 19 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(snomed): full pipeline done
Refs: #1442
  • Loading branch information
jonahkaye committed Apr 1, 2024
commit 4f48c40d6813d1e497b950659c4a2f02f216a8a9
34 changes: 0 additions & 34 deletions packages/utils/src/customer-requests/consolidated-query.ts

This file was deleted.

91 changes: 75 additions & 16 deletions packages/utils/src/customer-requests/full-snomed-pipeline.ts
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main customer facing output of this PR. A script that for a given customer, gets all their patients consolidated data and performs the filtering and MR summary generation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Full script for running this whole process

Original file line number Diff line number Diff line change
@@ -1,42 +1,101 @@
import { bundleToHtml } from "@metriport/core/external/aws/lambda-logic/bundle-to-html";
import fs from "fs";
import fs from "fs/promises";
import { convertHtmlTablesToCsv } from "./convert-html-to-csv";
import * as path from "path";
import { fullProcessing } from "../terminology-server/snomed-dedup-and-filter";
import { MetriportMedicalApi } from "@metriport/api-sdk";
import { getEnvVarOrFail } from "@metriport/core/util/env-var";
import * as dotenv from "dotenv";
import axios from "axios";
dotenv.config();

const apiKey = getEnvVarOrFail("API_KEY");
const apiLoadBalancerURL = getEnvVarOrFail("API_URL");
const fhirUrl = getEnvVarOrFail("FHIR_URL");
const cxId = getEnvVarOrFail("CX_ID");
const metriportApi: MetriportMedicalApi = new MetriportMedicalApi(apiKey);

const resultsDirectory = "./runs/consolidatedPatients";

async function fetchPatientIds(cxId: string): Promise<string[]> {
const url = `${apiLoadBalancerURL}/internal/patient/ids?cxId=${cxId}`;
try {
const response = await axios.get(url);
return response.data.patientIds;
} catch (error) {
console.error(`Error fetching patient IDs:`, error);
return [];
}
}

//eslint-disable-next-line
async function getFhirPatientData(patientId: string): Promise<any> {
const url = `${fhirUrl}/fhir/${cxId}/Patient/${patientId}/`;
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
console.error(`Error fetching FHIR data for patient ${patientId}:`, error);
}
Comment on lines +46 to +48
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is failing silently and the code will keep executing. Is that expected?

}

export async function ensureDirectory(): Promise<void> {
await fs.mkdir(resultsDirectory, { recursive: true });
}

async function fetchAndSavePatientData(patientId: string): Promise<void> {
try {
const data = await metriportApi.getPatientConsolidated(patientId);
const fhirPatient = await getFhirPatientData(patientId);
const resourceWrappedFhirPatient = { resource: fhirPatient };
if (!data.entry) {
data.entry = [];
}
data.entry.push(resourceWrappedFhirPatient);
const filePath = `${resultsDirectory}/${patientId}.json`;
await fs.writeFile(filePath, JSON.stringify(data, null, 2));
console.log(`Data saved for patient ${patientId}`);
} catch (error) {
console.error(`Error fetching and saving data for patient ${patientId}:`, error);
}
}

async function processPatients(): Promise<void> {
console.log("Checking if directory exists...");
await ensureDirectory();
console.log("Fetching patient IDs...");
const patientIds = await fetchPatientIds(cxId);
for (const patientId of patientIds) {
await fetchAndSavePatientData(patientId);
}
console.log("All patient data processed.");
}

// Function to process each JSON file
async function processFile(filePath: string) {
await fullProcessing(filePath);

const bundle = fs.readFileSync(filePath, "utf8");
const bundle = await fs.readFile(filePath, "utf8");
const bundleParsed = JSON.parse(bundle);

// Convert JSON to HTML
const html = bundleToHtml(bundleParsed);
const htmlOutputFilePath = filePath.replace(".json", ".html");
fs.writeFileSync(htmlOutputFilePath, html);
await fs.writeFile(htmlOutputFilePath, html);
console.log(`HTML file created at ${htmlOutputFilePath}`);

// Convert HTML to CSV
const csvContent = convertHtmlTablesToCsv(html);
const csvOutputFilePath = filePath.replace(".json", ".csv");
fs.writeFileSync(csvOutputFilePath, csvContent);
await fs.writeFile(csvOutputFilePath, csvContent);
console.log(`CSV file created at ${csvOutputFilePath}`);
}

// Main function to iterate through the directory
async function main() {
const targetPath = process.argv[2];

if (!targetPath) {
console.log("Usage: node medical-records-local.js <path-to-directory>");
process.exit(1);
}
await processPatients();

const files = fs.readdirSync(targetPath);
const files = await fs.readdir(resultsDirectory);
for (const file of files) {
const fullPath = path.join(targetPath, file);
const fullPath = path.join(resultsDirectory, file);
if (path.extname(fullPath) === ".json") {
console.log(`Processing file ${fullPath}`);
await processFile(fullPath);
}
}
Expand Down
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Analysis done on preconditions on sample patient set for reference:

Total #of Conditions in the directory: 401308
Total #of Conditions generated from <Precondition> in the directory: 685
Total #of Conditions generated from <Precondition> in the directory of type disorder: 56

15802004 with count 1 is a disorder: Dystonia (disorder)
16932000 with count 20 is a disorder: Nausea and vomiting (disorder)
37796009 with count 3 is a disorder: Migraine (disorder)
38341003 with count 3 is a disorder: Hypertensive disorder, systemic arterial (disorder)
39579001 with count 2 is a disorder: Anaphylaxis (disorder)
70153002 with count 3 is a disorder: Hemorrhoids (disorder)
193462001 with count 6 is a disorder: Insomnia (disorder)
242253008 with count 2 is a disorder: Overdose of opiate (disorder)
302866003 with count 4 is a disorder: Hypoglycemia (disorder)
419076005 with count 1 is a disorder: Allergic reaction (disorder)
422400008 with count 10 is a disorder: Vomiting (disorder)
860914002 with count 1 is a disorder: Erectile dysfunction (disorder)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add documentation explaining what it does and how to use it, please.

Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,6 @@ async function main() {
);
}

main();
if (require.main === module) {
main();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add documentation explaining what it does and how to use it, please.

Original file line number Diff line number Diff line change
Expand Up @@ -299,4 +299,6 @@ async function main() {
await fullProcessing(directoryPath);
}

main();
if (require.main === module) {
main();
}
Loading