diff --git a/README.md b/README.md index ca1b0f1..0a6d928 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,6 @@ # 解剖结构 - 模型的关系 1:1 or 1:n - 换版本重新测量 -- \ No newline at end of file + + +pnpm config set virtual-store-dir-max-length 70 \ No newline at end of file diff --git a/apps/desktop/electron/core/PythonManager.ts b/apps/desktop/electron/core/PythonManager.ts deleted file mode 100644 index 568e036..0000000 --- a/apps/desktop/electron/core/PythonManager.ts +++ /dev/null @@ -1,107 +0,0 @@ -// import http from "node:http"; -import path from "node:path"; -import { spawn, ChildProcess } from "node:child_process"; -import { BrowserWindow } from "electron"; -// import http from "node:http"; - -class PythonManager { - public flaskProcess: ChildProcess | null = null; - private intervalId: NodeJS.Timeout | null = null; - - constructor( - private mainWindow: BrowserWindow | null, - private url: string, - private interval = 5000 - ) {} - - // 启动 Python 服务 - public startFlask() { - if (this.flaskProcess) { - console.log("Flask service is already running."); - this.mainWindow?.webContents.send("flask", { running: true }); - return; - } - - // 使用 spawn 启动 Flask 服务 - this.flaskProcess = spawn(path.join(process.env.VITE_PUBLIC!, "main.exe")); - - // 实时获取 stdout 日志 - this.flaskProcess.stdout?.on("data", (data) => { - const message = data.toString(); - console.log(`Flask stdout: ${message}`); - this.mainWindow?.webContents.send("flask", { stdout: message }); - }); - - // 实时获取 stderr 日志 - this.flaskProcess.stderr?.on("data", (data) => { - const message = data.toString(); - console.error(`Flask stderr: ${message}`); - this.mainWindow?.webContents.send("flask-service:response", { - stderr: message, - }); - }); - - // 监听进程关闭事件 - this.flaskProcess.on("close", (code) => { - console.log(`Flask process exited with code ${code}`); - this.flaskProcess = null; - this.mainWindow?.webContents.send("flask-service:response", { - exited: true, - code, - }); - }); - - // 开始轮询服务状态 - // this.startCheckingFlaskStatus(); - } - - // 停止 Python 服务 - public stopFlask() { - if (this.flaskProcess) { - this.flaskProcess.kill(); - console.log("Flask service stopped."); - this.flaskProcess = null; - } - - // 停止轮询 - this.stopCheckingFlaskStatus(); - } - - // 检查 Flask 服务状态 - // private checkFlaskStatus() { - // if (!this.mainWindow) return; - - // http - // .get(this.url, (res) => { - // const { statusCode } = res; - // this.mainWindow?.webContents.send("flask-check", { - // running: statusCode === 200, - // }); - // }) - // .on("error", (err) => { - // console.error(`Error checking Flask service: ${err.message}`); - // this.mainWindow?.webContents.send("flask-check", { - // running: false, - // }); - // }); - // } - - // 开始轮询 Flask 服务状态 - // private startCheckingFlaskStatus() { - // if (this.intervalId) { - // console.log("Already checking Flask status."); - // return; - // } - // this.intervalId = setInterval(() => this.checkFlaskStatus(), this.interval); - // } - - // 停止轮询 Flask 服务状态 - private stopCheckingFlaskStatus() { - if (this.intervalId) { - clearInterval(this.intervalId); - this.intervalId = null; - } - } -} - -export default PythonManager; diff --git a/apps/desktop/electron/core/db.ts b/apps/desktop/electron/core/db.ts index 890bb35..9d5368d 100644 --- a/apps/desktop/electron/core/db.ts +++ b/apps/desktop/electron/core/db.ts @@ -3,7 +3,6 @@ import { JSONFilePreset } from "lowdb/node"; import { app } from "electron"; import { Low } from "node_modules/lowdb/lib/core/Low"; import { StructuredMetadata } from "./dicom"; -import { existsSync } from "node:fs"; import { merge } from "lodash"; export interface ICreateDatabase { diff --git a/apps/desktop/electron/ipcMainHandlers.ts b/apps/desktop/electron/ipcMainHandlers.ts index 60c129d..e83c598 100644 --- a/apps/desktop/electron/ipcMainHandlers.ts +++ b/apps/desktop/electron/ipcMainHandlers.ts @@ -9,7 +9,6 @@ import { import { db } from "./core/db"; import axios from "axios"; import path from "node:path"; -import { mkdirSync, statSync } from "fs"; import { mkdir, stat } from "fs/promises"; /** @@ -27,56 +26,62 @@ const registerIpcMainHandlers = (mainWindow: Electron.BrowserWindow | null) => { ipcMain.on("ai:task", (_, data) => { const { selectDicoms } = data; - const promises = selectDicoms.reduce((promiseChain, dicom) => { - return promiseChain.then(() => { - const { filePaths, PatientName, SeriesInstanceUID } = dicom; - const img_path = path.dirname(filePaths[0]); - const save_path = path.join( - app.getPath("userData"), - "output", - PatientName, - SeriesInstanceUID - ); - const params = { - img_path, - save_path, - pu: "GPU", - module: "root", - turbo: true, - }; + const promises = selectDicoms.reduce( + ( + promiseChain: Promise, + dicom: { filePaths: any; PatientName: any; SeriesInstanceUID: any } + ) => { + return promiseChain.then(() => { + const { filePaths, PatientName, SeriesInstanceUID } = dicom; + const img_path = path.dirname(filePaths[0]); + const save_path = path.join( + app.getPath("userData"), + "output", + PatientName, + SeriesInstanceUID + ); + const params = { + img_path, + save_path, + pu: "GPU", + module: "root", + turbo: true, + }; - const startTime = Date.now(); // 记录请求开始时间 - console.log( - `Request for ${PatientName} started at ${new Date( - startTime - ).toISOString()}` - ); - console.log(params); + const startTime = Date.now(); // 记录请求开始时间 + console.log( + `Request for ${PatientName} started at ${new Date( + startTime + ).toISOString()}` + ); + console.log(params); - return axios - .post("http://127.0.0.1:5000/root", { ...params }) - .then((response) => { - const endTime = Date.now(); // 记录请求结束时间 - const duration = (endTime - startTime) / 1000; // 计算耗时,单位为秒 - console.log( - `Response for ${PatientName} received at ${new Date( - endTime - ).toISOString()} (Duration: ${duration} seconds)` - ); - console.log(response.data); - }) - .catch((error) => { - const endTime = Date.now(); // 即使失败也记录结束时间 - const duration = (endTime - startTime) / 1000; - console.error( - `Error for ${PatientName} at ${new Date( - endTime - ).toISOString()} (Duration: ${duration} seconds)` - ); - console.error(error); - }); - }); - }, Promise.resolve()); // 从 resolve() 开始,依次链接每个 Promise + return axios + .post("http://127.0.0.1:5000/root", { ...params }) + .then((response) => { + const endTime = Date.now(); // 记录请求结束时间 + const duration = (endTime - startTime) / 1000; // 计算耗时,单位为秒 + console.log( + `Response for ${PatientName} received at ${new Date( + endTime + ).toISOString()} (Duration: ${duration} seconds)` + ); + console.log(response.data); + }) + .catch((error) => { + const endTime = Date.now(); // 即使失败也记录结束时间 + const duration = (endTime - startTime) / 1000; + console.error( + `Error for ${PatientName} at ${new Date( + endTime + ).toISOString()} (Duration: ${duration} seconds)` + ); + console.error(error); + }); + }); + }, + Promise.resolve() + ); // 从 resolve() 开始,依次链接每个 Promise const overallStartTime = Date.now(); // 记录总的开始时间 promises.then(() => { @@ -124,6 +129,81 @@ const registerIpcMainHandlers = (mainWindow: Electron.BrowserWindow | null) => { }); }); + ipcMain.on("one-step", async (event, dir) => { + const directory = path.resolve(dir); + const dcmPaths = await findDcmFiles(directory); + const batchSize = os.cpus().length * 1 || 10; + const items = await processFilesInBatches(dcmPaths, batchSize); + const structDicom = await structureMetadata(items); + // 存数据库 + const changeTime = Date.now(); + for (const item of structDicom) { + const existSeries = db.data.series.find( + (i) => i[keyProp] === item[keyProp] + ); + existSeries + ? Object.assign(existSeries, item, { updateTime: changeTime }) + : db.data.series.push({ + ...item, + createTime: changeTime, + updateTime: changeTime, + }); + await db.write(); + } + // 启动分析 + const promises = structDicom.reduce((promiseChain, dicom) => { + return promiseChain.then(() => { + const { filePaths, PatientName = "", SeriesInstanceUID = "" } = dicom; + const img_path = path.dirname(filePaths[0]); + const save_path = path.join( + app.getPath("userData"), + "output", + PatientName, + SeriesInstanceUID + ); + const params = { + img_path, + save_path, + pu: "GPU", + module: "root", + turbo: true, + }; + + const startTime = Date.now(); // 记录请求开始时间 + return axios + .post("http://127.0.0.1:5000/root", { ...params }) + .then((response) => { + const endTime = Date.now(); // 记录请求结束时间 + const duration = (endTime - startTime) / 1000; // 计算耗时,单位为秒 + event.reply( + "taskFinished", + `Response for ${PatientName} received at ${new Date( + endTime + ).toISOString()} (Duration: ${duration} seconds)` + ); + console.log(response); + }) + .catch((error) => { + const endTime = Date.now(); // 即使失败也记录结束时间 + const duration = (endTime - startTime) / 1000; + console.error( + `Error for ${PatientName} at ${new Date( + endTime + ).toISOString()} (Duration: ${duration} seconds)` + ); + console.error(error); + }); + }); + }, Promise.resolve()); // 从 resolve() 开始,依次链接每个 Promise + + const overallStartTime = Date.now(); // 记录总的开始时间 + promises.then(() => { + const overallEndTime = Date.now(); // 记录总的结束时间 + const overallDuration = (overallEndTime - overallStartTime) / 1000; // 总耗时 + event.reply("tasksFinished", overallDuration); + }); + }); + /** * api 获取 列表的中数据 */ diff --git a/apps/desktop/src/pages/Boot/index.tsx b/apps/desktop/src/pages/Boot/index.tsx index 6c5cea4..9601fbf 100644 --- a/apps/desktop/src/pages/Boot/index.tsx +++ b/apps/desktop/src/pages/Boot/index.tsx @@ -1,9 +1,6 @@ import { Button } from "@/components/ui/button"; import { motion } from "framer-motion"; import { useEffect, useState } from "react"; - - -import { useToast } from "@/components/ui/use-toast"; import { useLocation } from "react-router-dom"; import { SparkleIcon, Trash2 } from "lucide-react"; import { @@ -16,13 +13,12 @@ import { Card } from "@/components/ui/card"; import { Series } from "../Datasource/SeriesTable"; import { ScrollArea } from "@/components/ui/scroll-area"; - - const Boot = () => { const location = useLocation(); const selectDicoms = location.state?.selectDicoms ?? JSON.parse(localStorage.getItem("selectDicoms") ?? "[]"); + const [messageText, setMessageText] = useState(["进度信息简化"]); /** * windows系统右键启动应用菜单的入口路径 @@ -30,7 +26,6 @@ const Boot = () => { const [bootDirectoryPath, setBootDirectoryPath] = useState(""); const [tasks, setTasks] = useState(selectDicoms); - /** * 上传到electron主进程 */ @@ -45,11 +40,32 @@ const Boot = () => { }); }, []); + useEffect(() => { + if (bootDirectoryPath) { + window.ipcRenderer.send("one-step"); + } + return () => { + window.ipcRenderer.off("one-step", () => {}); + }; + }, [bootDirectoryPath]); + const handleEmptyTasks = () => { setTasks([]); localStorage.removeItem("selectDicoms"); }; + useEffect(() => { + window.ipcRenderer.on("tasksFinished", (_event, data) => { + setMessageText((p) => [...p, `总用时: ${data}`]); + }); + }, []); + + useEffect(() => { + window.ipcRenderer.on("taskFinished", (_event, data) => { + setMessageText((p) => [...p, data]); + }); + }, []); + return ( { className="h-full" >
- +
@@ -121,7 +134,9 @@ const Boot = () => {
- 分析进度将会呈现在这里 + {messageText.map((item) => ( +

{item}

+ ))}