feat: dicom文件hash去重 & 渲染进度

This commit is contained in:
mozzie 2024-08-31 02:18:35 +08:00
parent abf1cc06b5
commit 3ada54cf0f
4 changed files with 81 additions and 21 deletions

View File

@ -1,6 +1,7 @@
import path from "path";
import * as dicomParser from "dicom-parser";
import fs from "fs";
import crypto from 'crypto';
export interface StructuredData {
[SeriesInstanceUID: string]: ExtractMetadata[];
@ -128,35 +129,58 @@ export interface StructuredMetadata {
StudyInstanceUID?: string;
SeriesInstanceUID?: string;
PatientName?: string;
fileHash: string[]
}
export const structureMetadata = (
data: ExtractMetadata[]
): StructuredMetadata[] => {
export interface ScanProgress {
percentage: number
}
// 计算文件的哈希值
async function calculateFileHash(filePath: string): Promise<string> {
return new Promise((resolve, reject) => {
const hash = crypto.createHash('sha256');
const stream = fs.createReadStream(filePath);
stream.on('error', reject);
stream.pipe(hash).on('finish', () => resolve(hash.digest('hex')));
});
}
export const structureMetadata = async (
data: ExtractMetadata[],
progressCallback?: (progress: ScanProgress) => void
): Promise<StructuredMetadata[]> => {
const result: StructuredMetadata[] = [];
// 序列级别
const keyProp = 'SeriesInstanceUID'
data.forEach((item) => {
// 查找是否已经有相同 UID 和 PatientName 的条目
const existingEntry = result.find(
(entry) =>
entry.StudyInstanceUID === item.StudyInstanceUID &&
entry.SeriesInstanceUID === item.SeriesInstanceUID &&
entry.PatientName === item.PatientName
);
for (let i = 0; i < data.length; i++) {
const item = data[i]
const existItem = result.find((i) => i[keyProp] === item[keyProp]);
const hash = await calculateFileHash(item.filePath);
if (existingEntry) {
if (existItem) {
// 如果找到了相同的条目,合并 filePath
existingEntry.filePaths.push(item.filePath);
if (!existItem.fileHash.includes(hash)) {
existItem.filePaths.push(item.filePath);
existItem.fileHash.push(hash)
}
} else {
// 如果没有找到,创建一个新的条目
result.push({
filePaths: [item.filePath],
fileHash: [hash],
StudyInstanceUID: item.StudyInstanceUID,
SeriesInstanceUID: item.SeriesInstanceUID,
PatientName: item.PatientName,
});
}
});
const progress: ScanProgress = {
percentage: ((i + 1) / data.length) * 100
};
progressCallback?.(progress);
}
return result;
};

View File

@ -47,17 +47,19 @@ const registerIpcMainHandlers = (
running ? pythonManager.startFlask() : pythonManager.stopFlask();
});
ipcMain.on("scan-dicom", async () => {
ipcMain.on("scan-dicom", async (event) => {
const result = await dialog.showOpenDialog({
properties: ["openDirectory"],
});
if (result.canceled) return null;
const filePaths = result.filePaths[0];
const dcmPaths = await findDcmFiles(filePaths);
const items = await processFilesInBatches(dcmPaths, 4);
const structDicom = await structureMetadata(items);
Database.getDb().data.posts.push("hello world");
return structDicom;
const dcmPaths = await findDcmFiles(filePaths)
const batchSize = os.cpus().length * 1 || 10;
const items = await processFilesInBatches(dcmPaths, batchSize);
const structDicom = await structureMetadata(items, (progress) => {
event.reply('scan-progress', progress)
});
event.reply('scan-progress-done', structDicom)
});
};

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<title>Cvpilot AI</title>
</head>
<body>
<div id="root"></div>

View File

@ -1,12 +1,46 @@
import { Button } from "@/components/ui/button";
import { useEffect, useState } from "react";
interface ScanProgress {
percentage: number
}
export const Datasource = () => {
const [progress, setProgress] = useState<ScanProgress>()
const [result, setResult] = useState()
useEffect(() => {
window.ipcRenderer.on('scan-progress', (event, data) => {
setProgress(data)
if (data.error) return;
});
return () => {
window.ipcRenderer.off('scan-progress', () => { });
};
}, []);
useEffect(() => {
window.ipcRenderer.on('scan-progress-done', (event, data) => {
console.log('%capps\desktop\src\pages\Datasource\index.tsx:25 data', 'color: #007acc;', data);
setResult(data)
if (data.error) return;
});
return () => {
window.ipcRenderer.off('scan-progress-done', () => { });
};
}, []);
return (
<div className="p-4">
<div>
<Button onClick={() => window.ipcRenderer.send("scan-dicom")}>
</Button>
<div>{progress?.percentage}</div>
<div>{JSON.stringify(result)}</div>
</div>
</div>
);