Skip to content

Commit 1c8b406

Browse files
committed
Merge branch 'main' of github.com:ModusCreateOrg/app-med-ai-gen into ADE-200
2 parents 78522a2 + 7b0724b commit 1c8b406

File tree

11 files changed

+349
-29
lines changed

11 files changed

+349
-29
lines changed

backend/src/document-processor/services/aws-bedrock.service.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ For lab values:
7272
- Set "isCritical" to true for urgent medical situations
7373
- Provide brief "conclusion" about what the value means for health
7474
- Add brief "suggestions" based on the value
75-
- If reference ranges are missing, add "reference-ranges-missing" to missingInformation and use standard ranges
75+
- IMPORTANT: For ANY lab value where reference/normal ranges are not explicitly stated in the document, you MUST add "reference-ranges-missing" to the missingInformation array and use standard medical ranges
76+
- If you use standard ranges because the document lacks them, clearly mark this in your response
7677
7778
CRITICAL FORMATTING RULES:
7879
- Begin immediately with { and end with }
@@ -87,6 +88,7 @@ Common errors to avoid:
8788
- Starting with "This appears to be a medical report..."
8889
- Creating nested JSON structures
8990
- Placing data inside definition fields
91+
- IMPORTANT: Failing to add "reference-ranges-missing" to missingInformation when ANY lab value lacks explicit ranges
9092
9193
Document text:
9294
`;

backend/src/services/perplexity.service.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
22
import { ConfigService } from '@nestjs/config';
33
import axios from 'axios';
44
import { AwsSecretsService } from './aws-secrets.service';
5+
import { MedicalDocumentAnalysis } from 'src/document-processor/services/aws-bedrock.service';
56

67
export interface PerplexityMessage {
78
role: 'system' | 'user' | 'assistant';
@@ -275,11 +276,14 @@ export class PerplexityService {
275276
* @param originalText The original text of the medical document
276277
* @returns The corrected medical document analysis
277278
*/
278-
async reviewMedicalAnalysis(analysis: any, originalText: string): Promise<any> {
279+
async reviewMedicalAnalysis(
280+
analysis: MedicalDocumentAnalysis,
281+
originalText: string,
282+
): Promise<any> {
279283
this.logger.log('Reviewing medical document analysis with Perplexity');
280284

281285
const systemPrompt =
282-
'Medical information verification specialist. Verify analysis against trusted sources (Mayo Clinic, Cleveland Clinic, CDC, NIH, WHO, medical journals). Ensure accuracy of lab ranges, interpretations, and recommendations. Return only corrected JSON.';
286+
'Medical information verification specialist. Verify analysis against trusted sources (Mayo Clinic, Cleveland Clinic, CDC, NIH, WHO, medical journals). Ensure accuracy of lab ranges, interpretations, and recommendations. Return only corrected JSON. IMPORTANT: Do not modify the metadata object, especially preserve the metadata.missingInformation array exactly as provided.';
283287

284288
const analysisJson = JSON.stringify(analysis, null, 2);
285289

@@ -289,6 +293,7 @@ export class PerplexityService {
289293
`2. Interpretations of abnormal values\n` +
290294
`3. Medical conclusions and recommendations\n` +
291295
`4. Lab value categorizations\n\n` +
296+
`CRITICAL INSTRUCTION: Do NOT modify the metadata object. The metadata.missingInformation array must remain exactly as provided without any additions, removals, or changes.\n\n` +
292297
`Analysis JSON:\n${analysisJson}\n\n` +
293298
`Original Text:\n${originalText}\n\n` +
294299
`Return ONLY corrected JSON with identical structure. No preamble, explanation, or text before/after JSON.`;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
.confirmation-modal {
2+
--height: auto;
3+
--border-radius: 16px 16px 0 0;
4+
--box-shadow: none;
5+
align-items: flex-end;
6+
--background: #ffffff;
7+
8+
&__container {
9+
padding: 24px;
10+
width: 100%;
11+
}
12+
13+
&__title {
14+
font-family: 'Inter', sans-serif;
15+
font-size: 22px;
16+
font-weight: 600;
17+
color: #313e4c;
18+
margin: 0 0 16px;
19+
text-align: left;
20+
}
21+
22+
&__message {
23+
font-family: 'Inter', sans-serif;
24+
font-size: 16px;
25+
font-weight: 400;
26+
color: #313e4c;
27+
margin: 0 0 24px;
28+
text-align: left;
29+
line-height: 1.5;
30+
}
31+
32+
&__actions {
33+
display: flex;
34+
gap: 16px;
35+
}
36+
37+
&__button {
38+
flex: 1;
39+
min-height: 56px;
40+
margin: 0;
41+
--border-radius: 12px;
42+
font-size: 20px;
43+
font-weight: 600;
44+
text-transform: none;
45+
46+
&--cancel {
47+
--background: #ffffff;
48+
--background-hover: rgba(67, 95, 240, 0.04);
49+
--background-activated: rgba(67, 95, 240, 0.08);
50+
--color: #435ff0; /* Blue color for No button */
51+
--border-color: #435ff0;
52+
--border-width: 1px;
53+
--border-style: solid;
54+
--box-shadow: none;
55+
}
56+
57+
&--confirm {
58+
--background: #ffffff; /* White background for Yes button */
59+
--background-hover: rgba(175, 27, 63, 0.04);
60+
--background-activated: rgba(175, 27, 63, 0.08);
61+
--color: #af1b3f; /* Red color for Yes button */
62+
--border-color: #af1b3f; /* Red border for Yes button */
63+
--border-width: 1px;
64+
--border-style: solid;
65+
}
66+
}
67+
68+
// Media queries for larger screens
69+
@media screen and (min-width: 768px) {
70+
&__container {
71+
max-width: 500px;
72+
margin: 0 auto;
73+
}
74+
}
75+
76+
// Handle the pull indicator
77+
&::part(handle) {
78+
background: #D9D9D9;
79+
width: 36px;
80+
height: 4px;
81+
border-radius: 2px;
82+
margin-top: 12px;
83+
}
84+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import React from 'react';
2+
import { IonButton, IonModal } from '@ionic/react';
3+
import './ConfirmationModal.scss';
4+
5+
interface ConfirmationModalProps {
6+
isOpen: boolean;
7+
title: string;
8+
message: string;
9+
confirmText: string;
10+
cancelText: string;
11+
onConfirm: () => void;
12+
onCancel: () => void;
13+
itemName?: string;
14+
testid?: string;
15+
}
16+
17+
/**
18+
* A reusable confirmation modal component that presents as a bottom sheet
19+
* Used for confirming destructive actions like deleting or discarding items
20+
*/
21+
const ConfirmationModal: React.FC<ConfirmationModalProps> = ({
22+
isOpen,
23+
title,
24+
message,
25+
confirmText,
26+
cancelText,
27+
onConfirm,
28+
onCancel,
29+
itemName,
30+
testid = 'confirmation-modal',
31+
}) => {
32+
// Replace placeholder with actual item name if provided
33+
const formattedMessage = itemName
34+
? message.replace('{itemName}', `"${itemName}"`)
35+
: message;
36+
37+
return (
38+
<IonModal
39+
isOpen={isOpen}
40+
onDidDismiss={onCancel}
41+
className="confirmation-modal"
42+
data-testid={testid}
43+
>
44+
<div className="confirmation-modal__container">
45+
<h2 className="confirmation-modal__title">{title}</h2>
46+
47+
<p className="confirmation-modal__message">
48+
{formattedMessage}
49+
</p>
50+
51+
<div className="confirmation-modal__actions">
52+
<IonButton
53+
expand="block"
54+
fill="outline"
55+
className="confirmation-modal__button confirmation-modal__button--cancel"
56+
onClick={onCancel}
57+
data-testid={`${testid}-cancel`}
58+
>
59+
{cancelText}
60+
</IonButton>
61+
62+
<IonButton
63+
expand="block"
64+
fill="outline"
65+
className="confirmation-modal__button confirmation-modal__button--confirm"
66+
onClick={onConfirm}
67+
data-testid={`${testid}-confirm`}
68+
>
69+
{confirmText}
70+
</IonButton>
71+
</div>
72+
</div>
73+
</IonModal>
74+
);
75+
};
76+
77+
export default ConfirmationModal;

frontend/src/common/utils/i18n/resources/en/common.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@
7373
"loading": {
7474
"report": "Loading report..."
7575
},
76-
"no": "no",
76+
"no": "No",
7777
"updated": "updated",
7878
"welcome": "Welcome",
79-
"yes": "yes",
79+
"yes": "Yes",
8080
"pages": {
8181
"chat": {
8282
"title": "AI Assistant"

frontend/src/common/utils/i18n/resources/es/common.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@
7070
"loading": {
7171
"report": "Cargando informe..."
7272
},
73-
"no": "no",
73+
"no": "No",
7474
"updated": "actualizado",
7575
"welcome": "Bienvenido",
76-
"yes": "",
76+
"yes": "",
7777
"pages": {
7878
"chat": {
7979
"title": "Asistente IA"

frontend/src/common/utils/i18n/resources/fr/common.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@
7070
"loading": {
7171
"report": "Chargement du rapport..."
7272
},
73-
"no": "non",
73+
"no": "Non",
7474
"updated": "mis à jour",
7575
"welcome": "Bienvenu",
76-
"yes": "oui",
76+
"yes": "Oui",
7777
"pages": {
7878
"chat": {
7979
"title": "Assistant IA"

frontend/src/pages/Reports/ReportDetailPage.tsx

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import axios from 'axios';
77
import { MedicalReport } from '../../common/models/medicalReport';
88
import { useTranslation } from 'react-i18next';
99
import { getAuthConfig } from 'common/api/reportService';
10+
import { useToasts } from 'common/hooks/useToasts';
1011

1112
// Import components
1213
import ReportHeader from './components/ReportHeader';
@@ -35,6 +36,7 @@ const ReportDetailPage: React.FC = () => {
3536
const { reportId } = useParams<{ reportId: string }>();
3637
const history = useHistory();
3738
const { t } = useTranslation();
39+
const { createToast } = useToasts();
3840

3941
// Fetch report data using react-query
4042
const { data, isLoading, error } = useQuery<MedicalReport>({
@@ -85,8 +87,31 @@ const ReportDetailPage: React.FC = () => {
8587

8688
// Handle action buttons
8789
const handleDiscard = async () => {
88-
await axios.delete(`${API_URL}/api/reports/${reportId}`, await getAuthConfig());
89-
history.push('/tabs/home');
90+
try {
91+
await axios.delete(`${API_URL}/api/reports/${reportId}`, await getAuthConfig());
92+
93+
// Show toast notification
94+
createToast({
95+
message: t('report.discard.success', {
96+
ns: 'reportDetail',
97+
defaultValue: 'Report deleted successfully',
98+
}),
99+
duration: 2000,
100+
});
101+
102+
// Navigate back
103+
history.push('/tabs/home');
104+
} catch (error) {
105+
console.error('Error discarding report:', error);
106+
createToast({
107+
message: t('report.discard.error', {
108+
ns: 'reportDetail',
109+
defaultValue: 'Failed to delete report',
110+
}),
111+
duration: 2000,
112+
color: 'danger',
113+
});
114+
}
90115
};
91116

92117
const handleNewUpload = () => {
@@ -114,7 +139,12 @@ const ReportDetailPage: React.FC = () => {
114139
<InfoCard />
115140

116141
{/* Action buttons at the bottom */}
117-
<ActionButtons onDiscard={handleDiscard} onNewUpload={handleNewUpload} />
142+
<ActionButtons
143+
onDiscard={handleDiscard}
144+
onNewUpload={handleNewUpload}
145+
reportTitle={reportData.title || reportData.category}
146+
reportId={reportId}
147+
/>
118148
</IonContent>
119149
</IonPage>
120150
);

0 commit comments

Comments
 (0)