@omniradiology/omnirad 0.1.3
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/README.md +438 -0
- package/app/api/ai-config/route.ts +131 -0
- package/app/api/ai-config/test/route.ts +49 -0
- package/app/api/auth/auto-login/route.ts +66 -0
- package/app/api/auth/check/route.ts +17 -0
- package/app/api/auth/login/route.ts +72 -0
- package/app/api/auth/logout/route.ts +25 -0
- package/app/api/auth/me/route.ts +75 -0
- package/app/api/auth/password/route.ts +49 -0
- package/app/api/auth/setup/route.ts +63 -0
- package/app/api/auth/users/route.ts +100 -0
- package/app/api/auth/wipe/route.ts +27 -0
- package/app/api/compliance/anonymize/patient/[id]/route.ts +104 -0
- package/app/api/compliance/audit/route.ts +110 -0
- package/app/api/compliance/export/patient/[id]/route.ts +108 -0
- package/app/api/compliance/restrict/patient/[id]/route.ts +59 -0
- package/app/api/compliance/settings/route.ts +93 -0
- package/app/api/copilot/annotate/route.ts +94 -0
- package/app/api/copilot/chat/route.ts +238 -0
- package/app/api/copilot/history/route.ts +95 -0
- package/app/api/copilot/reports/route.ts +81 -0
- package/app/api/fhir/Bundle/report/[id]/route.ts +85 -0
- package/app/api/fhir/DiagnosticReport/[id]/route.ts +45 -0
- package/app/api/fhir/ImagingStudy/[id]/route.ts +57 -0
- package/app/api/fhir/Patient/[id]/route.ts +26 -0
- package/app/api/fhir/ServiceRequest/route.ts +85 -0
- package/app/api/fhir/config/route.ts +102 -0
- package/app/api/fhir/config/test-connection/route.ts +49 -0
- package/app/api/fhir/metadata/route.ts +51 -0
- package/app/api/pacs/metadata/route.ts +32 -0
- package/app/api/pacs/qido/instances/route.ts +39 -0
- package/app/api/pacs/qido/series/route.ts +38 -0
- package/app/api/pacs/qido/studies/route.ts +37 -0
- package/app/api/pacs/test/route.ts +30 -0
- package/app/api/pacs/wado/render/route.ts +51 -0
- package/app/api/patients/[id]/reports/route.ts +18 -0
- package/app/api/patients/[id]/route.ts +43 -0
- package/app/api/patients/merge/route.ts +57 -0
- package/app/api/patients/route.ts +67 -0
- package/app/api/patients/search/route.ts +25 -0
- package/app/api/reports/[id]/route.ts +84 -0
- package/app/api/reports/[id]/status/route.ts +87 -0
- package/app/api/reports/clear/route.ts +16 -0
- package/app/api/reports/route.ts +112 -0
- package/app/api/segmentation-config/route.ts +238 -0
- package/app/api/settings/route.ts +245 -0
- package/app/api/settings/test-supabase/route.ts +103 -0
- package/app/api/upload/route.ts +48 -0
- package/app/copilot/page.tsx +30 -0
- package/app/globals.css +141 -0
- package/app/history/page.tsx +242 -0
- package/app/icon.svg +3 -0
- package/app/layout.tsx +47 -0
- package/app/login/page.tsx +175 -0
- package/app/pacs/page.tsx +78 -0
- package/app/page.tsx +125 -0
- package/app/patients/[id]/page.tsx +315 -0
- package/app/patients/page.tsx +110 -0
- package/app/profile/page.tsx +208 -0
- package/app/reports/page.tsx +432 -0
- package/app/settings/page.tsx +454 -0
- package/app/setup/page.tsx +199 -0
- package/components/admin/AuditLogTable.tsx +293 -0
- package/components/copilot/ActivityIndicator.tsx +215 -0
- package/components/copilot/ChatHistoryPanel.tsx +140 -0
- package/components/copilot/ChatMessage.tsx +251 -0
- package/components/copilot/ClickableReference.tsx +40 -0
- package/components/copilot/CopilotCornerstoneViewer.tsx +562 -0
- package/components/copilot/CopilotPanel.tsx +311 -0
- package/components/copilot/FindingsList.tsx +75 -0
- package/components/copilot/ViewerPanel.tsx +460 -0
- package/components/copilot/WorkspaceLayout.tsx +398 -0
- package/components/dashboard/AIConfigPanel.tsx +339 -0
- package/components/dashboard/AppearancePanel.tsx +491 -0
- package/components/dashboard/ApprovalModal.tsx +163 -0
- package/components/dashboard/CollaborationPanel.tsx +134 -0
- package/components/dashboard/CopilotConfigPanel.tsx +337 -0
- package/components/dashboard/DicomViewer.tsx +645 -0
- package/components/dashboard/FhirIntegrationPanel.tsx +331 -0
- package/components/dashboard/FullReportOverlay.tsx +269 -0
- package/components/dashboard/ImageViewer.tsx +541 -0
- package/components/dashboard/PatientForm.tsx +597 -0
- package/components/dashboard/RejectionModal.tsx +74 -0
- package/components/dashboard/ReportEditor.tsx +160 -0
- package/components/dashboard/ReportTemplates.tsx +729 -0
- package/components/dashboard/ReportView.tsx +539 -0
- package/components/dashboard/SegmentationConfigPanel.tsx +490 -0
- package/components/dashboard/StudyPlaceholder.tsx +17 -0
- package/components/dashboard/SupabaseIntegrationPanel.tsx +345 -0
- package/components/dashboard/UserManagementPanel.tsx +272 -0
- package/components/layout/ClientLayout.tsx +39 -0
- package/components/layout/Header.tsx +20 -0
- package/components/layout/Sidebar.tsx +119 -0
- package/components/pacs/PacsImageViewerModal.tsx +121 -0
- package/components/pacs/PacsSearchFilters.tsx +117 -0
- package/components/pacs/PacsSeriesViewer.tsx +190 -0
- package/components/pacs/PacsStudyTable.tsx +113 -0
- package/components/patients/patient-card.tsx +117 -0
- package/components/patients/patient-header.tsx +122 -0
- package/components/patients/patient-search.tsx +137 -0
- package/components/patients/patient-timeline.tsx +153 -0
- package/components/settings/ComplianceSettingsPanel.tsx +278 -0
- package/components/settings/SecurityPanel.tsx +418 -0
- package/components/ui/badge.tsx +19 -0
- package/components/ui/basic.tsx +156 -0
- package/db/index.ts +350 -0
- package/db/migrations/0000_odd_quasimodo.sql +117 -0
- package/db/migrations/meta/0000_snapshot.json +778 -0
- package/db/migrations/meta/_journal.json +13 -0
- package/db/schema.ts +239 -0
- package/drizzle.config.ts +10 -0
- package/lib/api.ts +689 -0
- package/lib/auth.ts +22 -0
- package/lib/copilot/action-executor.ts +94 -0
- package/lib/copilot/action-types.ts +72 -0
- package/lib/copilot/coordinate-mapper.ts +84 -0
- package/lib/dicomImageExtractor.ts +103 -0
- package/lib/dicomMetadataParser.ts +111 -0
- package/lib/fhir/client.ts +25 -0
- package/lib/fhir/constants.ts +21 -0
- package/lib/fhir/diagnostic-report.ts +88 -0
- package/lib/fhir/helpers.ts +73 -0
- package/lib/fhir/imaging-study.ts +49 -0
- package/lib/fhir/patient.ts +55 -0
- package/lib/fhir/service-request.ts +85 -0
- package/lib/fhir.ts +6 -0
- package/lib/pacs/dicom-utils.ts +72 -0
- package/lib/pacs/dicomweb.ts +72 -0
- package/lib/pacs/server-utils.ts +37 -0
- package/lib/patients.ts +25 -0
- package/lib/pdfHelper.ts +119 -0
- package/lib/reportHtmlGenerator.ts +581 -0
- package/lib/security/audit.ts +180 -0
- package/lib/security/authz.ts +246 -0
- package/lib/security/phi-redaction.ts +156 -0
- package/lib/security/rate-limit.ts +106 -0
- package/lib/security/secrets.ts +179 -0
- package/lib/supabase.ts +72 -0
- package/lib/utils.ts +6 -0
- package/next.config.ts +35 -0
- package/package.json +76 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/logo.svg +8 -0
- package/public/next.svg +1 -0
- package/public/omnirad-favicon.svg +8 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/tsconfig.json +34 -0
- package/types/copilot-viewer.ts +155 -0
- package/types/copilot.ts +105 -0
- package/types/fhir.ts +21 -0
- package/types/html2pdf.d.ts +20 -0
- package/types/index.ts +139 -0
- package/types/pacs.ts +41 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "next"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": [
|
|
26
|
+
"next-env.d.ts",
|
|
27
|
+
"**/*.ts",
|
|
28
|
+
"**/*.tsx",
|
|
29
|
+
".next/types/**/*.ts",
|
|
30
|
+
".next/dev/types/**/*.ts",
|
|
31
|
+
"**/*.mts"
|
|
32
|
+
],
|
|
33
|
+
"exclude": ["node_modules", "scripts", "old_omnirad"]
|
|
34
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// ─── Copilot Viewer Action Types ─────────────────────────────────────────────
|
|
2
|
+
// Expanded viewer action system supporting annotations, segmentations, and AI findings.
|
|
3
|
+
|
|
4
|
+
// ── Navigate Action ──────────────────────────────────────────────────────────
|
|
5
|
+
export interface NavigateAction {
|
|
6
|
+
type: "navigate";
|
|
7
|
+
action: "jump_to_slice";
|
|
8
|
+
slice: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// ── Annotation Action ────────────────────────────────────────────────────────
|
|
12
|
+
export interface AnnotationAction {
|
|
13
|
+
type: "annotation";
|
|
14
|
+
action:
|
|
15
|
+
| "create_bounding_box_annotation"
|
|
16
|
+
| "create_circle_annotation"
|
|
17
|
+
| "create_arrow_annotation"
|
|
18
|
+
| "create_probe_annotation"
|
|
19
|
+
| "create_rectangle_annotation";
|
|
20
|
+
annotation_id: string;
|
|
21
|
+
slice?: number;
|
|
22
|
+
label: string;
|
|
23
|
+
label_mode?: "always" | "on_select" | "hidden";
|
|
24
|
+
color?: string;
|
|
25
|
+
confidence?: number;
|
|
26
|
+
// Bounding box / rectangle
|
|
27
|
+
x?: number;
|
|
28
|
+
y?: number;
|
|
29
|
+
width?: number;
|
|
30
|
+
height?: number;
|
|
31
|
+
// Circle
|
|
32
|
+
center_x?: number;
|
|
33
|
+
center_y?: number;
|
|
34
|
+
radius?: number;
|
|
35
|
+
// Arrow / probe
|
|
36
|
+
start_x?: number;
|
|
37
|
+
start_y?: number;
|
|
38
|
+
end_x?: number;
|
|
39
|
+
end_y?: number;
|
|
40
|
+
metadata?: AnnotationMetadata;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ── Segmentation Action ──────────────────────────────────────────────────────
|
|
44
|
+
export interface SegmentationAction {
|
|
45
|
+
type: "segmentation";
|
|
46
|
+
action: "render_mask_overlay" | "render_contour_overlay" | "clear_ai_segmentations";
|
|
47
|
+
segmentation_id?: string;
|
|
48
|
+
slice?: number;
|
|
49
|
+
label?: string;
|
|
50
|
+
label_mode?: "always" | "on_select" | "hidden";
|
|
51
|
+
color?: string;
|
|
52
|
+
opacity?: number;
|
|
53
|
+
bbox?: [number, number, number, number];
|
|
54
|
+
mask_reference?: string;
|
|
55
|
+
contour_points?: [number, number][];
|
|
56
|
+
metadata?: AnnotationMetadata;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ── Viewport Action ──────────────────────────────────────────────────────────
|
|
60
|
+
export interface ViewportAction {
|
|
61
|
+
type: "viewport";
|
|
62
|
+
action: "zoom_to_region" | "reset_viewport";
|
|
63
|
+
x?: number;
|
|
64
|
+
y?: number;
|
|
65
|
+
width?: number;
|
|
66
|
+
height?: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ── Clear Action ─────────────────────────────────────────────────────────────
|
|
70
|
+
export interface ClearAction {
|
|
71
|
+
type: "clear";
|
|
72
|
+
action: "clear_ai_annotations" | "clear_ai_segmentations" | "clear_all_ai_findings";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ── Annotation Metadata ──────────────────────────────────────────────────────
|
|
76
|
+
export interface AnnotationMetadata {
|
|
77
|
+
source: "ai" | "manual";
|
|
78
|
+
model?: "medsam3" | "llm" | string;
|
|
79
|
+
prompt?: string;
|
|
80
|
+
prompt_variants?: string[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ── Union of all AI viewer actions ───────────────────────────────────────────
|
|
84
|
+
export type AIViewerAction =
|
|
85
|
+
| NavigateAction
|
|
86
|
+
| AnnotationAction
|
|
87
|
+
| SegmentationAction
|
|
88
|
+
| ViewportAction
|
|
89
|
+
| ClearAction;
|
|
90
|
+
|
|
91
|
+
// ── Finding Summary ──────────────────────────────────────────────────────────
|
|
92
|
+
export interface FindingSummary {
|
|
93
|
+
name: string;
|
|
94
|
+
confidence?: number;
|
|
95
|
+
annotation_id: string;
|
|
96
|
+
segmentation_id?: string;
|
|
97
|
+
slice?: number;
|
|
98
|
+
prompt?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ── Annotate API Request ─────────────────────────────────────────────────────
|
|
102
|
+
export interface CopilotAnnotateRequest {
|
|
103
|
+
message: string;
|
|
104
|
+
session_id?: string;
|
|
105
|
+
patient_id?: string;
|
|
106
|
+
report_id?: string;
|
|
107
|
+
study_uid?: string;
|
|
108
|
+
series_uid?: string;
|
|
109
|
+
current_slice?: number;
|
|
110
|
+
total_slices?: number;
|
|
111
|
+
modality?: string;
|
|
112
|
+
report_text?: string;
|
|
113
|
+
viewport_image?: string; // base64 of current viewport
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── Annotate API Response ────────────────────────────────────────────────────
|
|
117
|
+
export interface CopilotAnnotateResponse {
|
|
118
|
+
reply: string;
|
|
119
|
+
viewer_actions: AIViewerAction[];
|
|
120
|
+
findings_summary: FindingSummary[];
|
|
121
|
+
error?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ── Segmentation Backend Config ──────────────────────────────────────────────
|
|
125
|
+
export interface SegmentationConfig {
|
|
126
|
+
id?: string;
|
|
127
|
+
deploymentMode: "localhost" | "custom_api";
|
|
128
|
+
providerName: string;
|
|
129
|
+
modelName: string;
|
|
130
|
+
baseUrl: string;
|
|
131
|
+
healthEndpoint: string;
|
|
132
|
+
predictEndpoint: string;
|
|
133
|
+
apiSecretKey?: string;
|
|
134
|
+
timeoutSeconds: number;
|
|
135
|
+
supportsContours: boolean;
|
|
136
|
+
supports3D: boolean;
|
|
137
|
+
returnsMask: boolean;
|
|
138
|
+
returnsBox: boolean;
|
|
139
|
+
isActive: boolean;
|
|
140
|
+
createdAt?: string;
|
|
141
|
+
updatedAt?: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── Cornerstone Viewer Ref API ───────────────────────────────────────────────
|
|
145
|
+
export interface CopilotViewerRef {
|
|
146
|
+
jumpToSlice: (slice: number) => void;
|
|
147
|
+
addAnnotation: (action: AnnotationAction) => void;
|
|
148
|
+
addSegmentation: (action: SegmentationAction) => void;
|
|
149
|
+
clearAIFindings: () => void;
|
|
150
|
+
zoomToRegion: (x: number, y: number, width: number, height: number) => void;
|
|
151
|
+
resetViewport: () => void;
|
|
152
|
+
getCurrentSlice: () => number;
|
|
153
|
+
getTotalSlices: () => number;
|
|
154
|
+
getCurrentImageBase64: () => string | null;
|
|
155
|
+
}
|
package/types/copilot.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// ─── AI Copilot Types ────────────────────────────────────────────────────────
|
|
2
|
+
|
|
3
|
+
// Viewer Action — structured command from AI to control the viewer panel
|
|
4
|
+
export type ViewerAction =
|
|
5
|
+
| { type: 'OPEN_REPORT'; reportId: string; patientName?: string }
|
|
6
|
+
| { type: 'OPEN_DICOM'; studyId: string; reportId?: string; slice?: number }
|
|
7
|
+
| { type: 'OPEN_METADATA'; patientId: string }
|
|
8
|
+
| { type: 'SWITCH_TAB'; tab: ViewerTab }
|
|
9
|
+
| { type: 'COMPARE_VIEW'; reportId1: string; reportId2: string }
|
|
10
|
+
| null;
|
|
11
|
+
|
|
12
|
+
export type ViewerTab = 'dicom' | 'report' | 'metadata';
|
|
13
|
+
|
|
14
|
+
// Reference — clickable link in chat messages
|
|
15
|
+
export interface Reference {
|
|
16
|
+
id: string;
|
|
17
|
+
type: 'report' | 'study' | 'scan' | 'patient';
|
|
18
|
+
label: string;
|
|
19
|
+
viewerAction: ViewerAction;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// AI Chat Response from the backend
|
|
23
|
+
export interface AIChatResponse {
|
|
24
|
+
message: string;
|
|
25
|
+
viewerActions: ViewerAction[];
|
|
26
|
+
references: Reference[];
|
|
27
|
+
error?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Chat message stored in state / database
|
|
31
|
+
export interface ChatMessage {
|
|
32
|
+
id: string;
|
|
33
|
+
role: 'user' | 'assistant';
|
|
34
|
+
content: string | any[];
|
|
35
|
+
viewerActions?: ViewerAction[];
|
|
36
|
+
references?: Reference[];
|
|
37
|
+
timestamp: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Chat session summary
|
|
41
|
+
export interface ChatSession {
|
|
42
|
+
sessionId: string;
|
|
43
|
+
patientId?: string;
|
|
44
|
+
patientName?: string;
|
|
45
|
+
lastMessage: string;
|
|
46
|
+
messageCount: number;
|
|
47
|
+
createdAt: string;
|
|
48
|
+
updatedAt: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Patient context passed to the AI
|
|
52
|
+
export interface CopilotPatientContext {
|
|
53
|
+
patientId?: string | null;
|
|
54
|
+
currentReportId?: string | null;
|
|
55
|
+
patientName?: string | null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Quick action presets
|
|
59
|
+
export interface QuickAction {
|
|
60
|
+
label: string;
|
|
61
|
+
prompt: string;
|
|
62
|
+
icon: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ─── Activity Indicator Types ────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
export interface ActivityStep {
|
|
68
|
+
label: string;
|
|
69
|
+
tool: string | null;
|
|
70
|
+
timestamp: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ActivityState {
|
|
74
|
+
isActive: boolean;
|
|
75
|
+
currentStatus: string;
|
|
76
|
+
currentLabel: string;
|
|
77
|
+
currentTool: string | null;
|
|
78
|
+
completedSteps: ActivityStep[];
|
|
79
|
+
startedAt: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const INITIAL_ACTIVITY_STATE: ActivityState = {
|
|
83
|
+
isActive: false,
|
|
84
|
+
currentStatus: "",
|
|
85
|
+
currentLabel: "",
|
|
86
|
+
currentTool: null,
|
|
87
|
+
completedSteps: [],
|
|
88
|
+
startedAt: 0,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Re-export copilot viewer types for convenient access
|
|
92
|
+
export type {
|
|
93
|
+
AIViewerAction,
|
|
94
|
+
NavigateAction,
|
|
95
|
+
AnnotationAction,
|
|
96
|
+
SegmentationAction,
|
|
97
|
+
ViewportAction as ViewportAIAction,
|
|
98
|
+
ClearAction,
|
|
99
|
+
AnnotationMetadata,
|
|
100
|
+
FindingSummary,
|
|
101
|
+
CopilotAnnotateRequest,
|
|
102
|
+
CopilotAnnotateResponse,
|
|
103
|
+
SegmentationConfig,
|
|
104
|
+
CopilotViewerRef,
|
|
105
|
+
} from "./copilot-viewer";
|
package/types/fhir.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { InferSelectModel, InferInsertModel } from "drizzle-orm";
|
|
2
|
+
import { reports, worklistOrders } from "../db/schema";
|
|
3
|
+
import { Patient, ReportData } from "./index";
|
|
4
|
+
|
|
5
|
+
export type ReportRow = InferSelectModel<typeof reports>;
|
|
6
|
+
export type WorklistOrder = InferSelectModel<typeof worklistOrders>;
|
|
7
|
+
export type OmniRadWorklistOrderInput = InferInsertModel<typeof worklistOrders>;
|
|
8
|
+
|
|
9
|
+
export interface DiagnosticReportInput {
|
|
10
|
+
report: ReportRow;
|
|
11
|
+
reportData: ReportData;
|
|
12
|
+
patient?: Patient;
|
|
13
|
+
pdfBase64?: string;
|
|
14
|
+
serviceRequestId?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ImagingStudyInput {
|
|
18
|
+
report: ReportRow;
|
|
19
|
+
reportData: ReportData;
|
|
20
|
+
patient?: Patient;
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare module 'html2pdf.js' {
|
|
2
|
+
interface Html2PdfOptions {
|
|
3
|
+
margin?: number | [number, number] | [number, number, number, number];
|
|
4
|
+
filename?: string;
|
|
5
|
+
image?: { type: string; quality: number };
|
|
6
|
+
enableLinks?: boolean;
|
|
7
|
+
html2canvas?: any;
|
|
8
|
+
jsPDF?: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface Html2PdfWorker {
|
|
12
|
+
from(element: HTMLElement | string): Html2PdfWorker;
|
|
13
|
+
set(options: Html2PdfOptions): Html2PdfWorker;
|
|
14
|
+
save(): Promise<void>;
|
|
15
|
+
outputPdf(type?: string): Promise<string | Blob | ArrayBuffer>; // Add more if needed
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function html2pdf(): Html2PdfWorker;
|
|
19
|
+
export default html2pdf;
|
|
20
|
+
}
|
package/types/index.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
export type ReportStatus = 'Pending' | 'Approved' | 'Rejected' | 'Final';
|
|
2
|
+
|
|
3
|
+
export interface Patient {
|
|
4
|
+
id: string;
|
|
5
|
+
patientIdNumber?: string;
|
|
6
|
+
patientName: string;
|
|
7
|
+
dob?: string;
|
|
8
|
+
age?: number;
|
|
9
|
+
gender?: string;
|
|
10
|
+
mobile?: string;
|
|
11
|
+
address?: string;
|
|
12
|
+
contactInfo?: string;
|
|
13
|
+
notes?: string;
|
|
14
|
+
createdAt: string;
|
|
15
|
+
updatedAt?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ReportFooter {
|
|
19
|
+
prepared_by: string;
|
|
20
|
+
department: string;
|
|
21
|
+
report_status: ReportStatus;
|
|
22
|
+
approved_by?: string;
|
|
23
|
+
approved_at?: string;
|
|
24
|
+
signature?: string;
|
|
25
|
+
rejection_reason?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Comment {
|
|
29
|
+
id: string;
|
|
30
|
+
author: string;
|
|
31
|
+
role: string;
|
|
32
|
+
text: string;
|
|
33
|
+
timestamp: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface AuditLog {
|
|
37
|
+
id: string;
|
|
38
|
+
action: string;
|
|
39
|
+
user: string;
|
|
40
|
+
timestamp: string;
|
|
41
|
+
details?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface PatientContext {
|
|
45
|
+
fullName: string;
|
|
46
|
+
patientId: string;
|
|
47
|
+
age: number;
|
|
48
|
+
dob?: string;
|
|
49
|
+
gender: string;
|
|
50
|
+
indication: string;
|
|
51
|
+
symptoms: string;
|
|
52
|
+
history: string;
|
|
53
|
+
modality: string;
|
|
54
|
+
image?: File | null;
|
|
55
|
+
images?: File[];
|
|
56
|
+
isDicom?: boolean;
|
|
57
|
+
dicomMetadata?: any; // Will use DicomMetadata type
|
|
58
|
+
isPacs?: boolean;
|
|
59
|
+
pacsData?: any;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface Finding {
|
|
63
|
+
anatomical_region: string;
|
|
64
|
+
observation: string;
|
|
65
|
+
status: "normal" | "abnormal";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface ReportData {
|
|
69
|
+
report_header: {
|
|
70
|
+
hospital_name: string;
|
|
71
|
+
department: string;
|
|
72
|
+
report_title: string;
|
|
73
|
+
report_id: string;
|
|
74
|
+
report_date: string;
|
|
75
|
+
};
|
|
76
|
+
patient: {
|
|
77
|
+
name: string;
|
|
78
|
+
patient_id?: string;
|
|
79
|
+
age: number;
|
|
80
|
+
dob?: string;
|
|
81
|
+
gender: string;
|
|
82
|
+
};
|
|
83
|
+
clinical_information: {
|
|
84
|
+
symptoms: string;
|
|
85
|
+
history: string;
|
|
86
|
+
indication: string;
|
|
87
|
+
};
|
|
88
|
+
study: {
|
|
89
|
+
modality: string;
|
|
90
|
+
examination: string;
|
|
91
|
+
views: string;
|
|
92
|
+
};
|
|
93
|
+
findings: Finding[];
|
|
94
|
+
impression: string[];
|
|
95
|
+
urgency: "Routine" | "Urgent" | "Critical";
|
|
96
|
+
recommendations: string[];
|
|
97
|
+
report_footer: ReportFooter;
|
|
98
|
+
disclaimer: string;
|
|
99
|
+
image_data?: string; // Base64 encoded image
|
|
100
|
+
images_data?: string[]; // Array of Base64 encoded images
|
|
101
|
+
collaboration?: {
|
|
102
|
+
comments: Comment[];
|
|
103
|
+
logs: AuditLog[];
|
|
104
|
+
};
|
|
105
|
+
pacs_info?: {
|
|
106
|
+
study_uid: string;
|
|
107
|
+
series_uid: string;
|
|
108
|
+
source: string;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface DicomMetadata {
|
|
113
|
+
patientName?: string;
|
|
114
|
+
patientId?: string;
|
|
115
|
+
patientBirthDate?: string;
|
|
116
|
+
patientAge?: string;
|
|
117
|
+
patientSex?: string;
|
|
118
|
+
studyDate?: string;
|
|
119
|
+
studyTime?: string;
|
|
120
|
+
modality?: string;
|
|
121
|
+
institutionName?: string;
|
|
122
|
+
studyDescription?: string;
|
|
123
|
+
seriesDescription?: string;
|
|
124
|
+
bodyPartExamined?: string;
|
|
125
|
+
referringPhysicianName?: string;
|
|
126
|
+
accessionNumber?: string;
|
|
127
|
+
transferSyntaxUID?: string;
|
|
128
|
+
rows?: number;
|
|
129
|
+
columns?: number;
|
|
130
|
+
numberOfFrames?: number;
|
|
131
|
+
bitsAllocated?: number;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface DicomExtractionResult {
|
|
135
|
+
success: boolean;
|
|
136
|
+
metadata?: DicomMetadata;
|
|
137
|
+
images?: string[]; // Base64 JPEGs or Blob URLs
|
|
138
|
+
error?: string;
|
|
139
|
+
}
|
package/types/pacs.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface PacsConfig {
|
|
2
|
+
pacsOrthancUrl: string;
|
|
3
|
+
pacsAuthType: 'none' | 'basic' | 'bearer';
|
|
4
|
+
pacsUsername?: string;
|
|
5
|
+
pacsPassword?: string;
|
|
6
|
+
pacsBearerToken?: string;
|
|
7
|
+
pacsAeTitle?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface DicomStudy {
|
|
11
|
+
id: string; // Internal identifier
|
|
12
|
+
studyInstanceUid: string;
|
|
13
|
+
patientName: string;
|
|
14
|
+
patientId: string;
|
|
15
|
+
patientBirthDate?: string;
|
|
16
|
+
patientAge?: string;
|
|
17
|
+
patientSex?: string;
|
|
18
|
+
studyDate: string;
|
|
19
|
+
studyTime: string;
|
|
20
|
+
accessionNumber: string;
|
|
21
|
+
studyDescription: string;
|
|
22
|
+
modalitiesInStudy: string[];
|
|
23
|
+
numberOfStudyRelatedSeries: number;
|
|
24
|
+
numberOfStudyRelatedInstances: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface DicomSeries {
|
|
28
|
+
studyInstanceUid: string;
|
|
29
|
+
seriesInstanceUid: string;
|
|
30
|
+
seriesNumber: number;
|
|
31
|
+
modality: string;
|
|
32
|
+
seriesDescription: string;
|
|
33
|
+
numberOfSeriesRelatedInstances: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface DicomInstance {
|
|
37
|
+
studyInstanceUid: string;
|
|
38
|
+
seriesInstanceUid: string;
|
|
39
|
+
sopInstanceUid: string;
|
|
40
|
+
instanceNumber: number;
|
|
41
|
+
}
|