Skip to content

Commit 2e2a3d1

Browse files
authored
Merge pull request #113 from ModusCreateOrg/ADE-66
Refactor AwsBedrockService medical analysis prompt and enhance PerplexityService prompts for clarity
2 parents 7b9ddb1 + ab1056c commit 2e2a3d1

File tree

4 files changed

+183
-130
lines changed

4 files changed

+183
-130
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ describe('AwsBedrockService', () => {
219219
// Verify the invokeBedrock was called with the correct prompt
220220
expect(service['invokeBedrock']).toHaveBeenCalled();
221221
const prompt = (service['invokeBedrock'] as any).mock.calls[0][0];
222-
expect(prompt).toContain('Please analyze this medical document carefully');
222+
expect(prompt).toContain('Analyze this medical document with focus on lab reports');
223223
});
224224

225225
it('should correctly format the request for Claude models', async () => {
@@ -242,7 +242,7 @@ describe('AwsBedrockService', () => {
242242
// Verify the invokeBedrock was called with the correct prompt
243243
expect(service['invokeBedrock']).toHaveBeenCalled();
244244
const prompt = (service['invokeBedrock'] as any).mock.calls[0][0];
245-
expect(prompt).toContain('Please analyze this medical document carefully');
245+
expect(prompt).toContain('Analyze this medical document with focus on lab reports');
246246
});
247247

248248
it('should throw an error for invalid input', async () => {

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

Lines changed: 30 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -45,30 +45,17 @@ export class AwsBedrockService {
4545
private readonly inferenceProfileArn?: string;
4646

4747
// Medical document analysis prompt
48-
private readonly medicalAnalysisPrompt = `Please analyze this medical document carefully, with specific attention to medical lab reports.
49-
50-
Look for and extract the following information:
51-
1. Document title or main subject based on content
52-
2. Document category based on organ system focus
53-
3. Lab test values with their normal ranges and whether they are normal, high, or low (particularly important for blood work, metabolic panels, etc.)
54-
4. Any diagnoses, findings, or medical observations with details and recommendations
55-
5. Analyze if this is a medical document (lab report, test result, medical chart, prescription, etc.) and provide confidence level
56-
57-
This document may be a lab report showing blood work or other test results, so please pay special attention to tables, numeric values, reference ranges, and medical terminology.
58-
59-
IMPORTANT: Base your analysis on information from multiple trusted medical sources and authorities, including but not limited to:
60-
- Mayo Clinic
61-
- Cleveland Clinic
62-
- CDC (Centers for Disease Control and Prevention)
63-
- NIH (National Institutes of Health)
64-
- WHO (World Health Organization)
65-
- American Medical Association
66-
- American Heart Association
67-
- American Academy of Pediatrics
68-
- UpToDate
69-
- MedlinePlus
70-
71-
Format the response as a JSON object with the following structure:
48+
private readonly medicalAnalysisPrompt = `Analyze this medical document with focus on lab reports. Extract:
49+
50+
1. Title/subject from content
51+
2. Category: "heart" (cardiac focus), "brain" (neurological focus), or "general" (all else)
52+
3. Lab values with ranges and status (normal/high/low)
53+
4. Diagnoses, findings, and recommendations
54+
5. Medical document verification with confidence level
55+
56+
Reference trusted sources: Mayo Clinic, Cleveland Clinic, CDC, NIH, WHO, AMA, etc.
57+
58+
Return ONLY a JSON object with this structure:
7259
{
7360
"title": string,
7461
"category": string,
@@ -81,89 +68,25 @@ Format the response as a JSON object with the following structure:
8168
}
8269
}
8370
84-
For the title field, create a concise title that summarizes what the document is about (e.g., "Complete Blood Count Results", "Liver Function Test", "MRI Report").
85-
For the category field, you MUST choose exactly one of these three values:
86-
- "heart" - if the document focuses primarily on cardiac/cardiovascular issues or tests
87-
- "brain" - if the document focuses primarily on neurological issues or brain-related tests
88-
- "general" - for all other medical documents, or when the focus spans multiple systems
89-
90-
Set isMedicalReport to true if you see ANY medical content such as lab values, medical terminology, doctor's notes, or prescription information.
91-
Set confidence between 0 and 1 based on document clarity and how confident you are about the medical nature of the document.
92-
93-
94-
This is extremely important: If you see ANY lab values, numbers with units, or medical terminology, please consider this a medical document even if you're not 100% certain.
95-
96-
When extracting lab values:
97-
1. Look for tables with numeric values and reference ranges
98-
2. Include any values even if you're not sure of the meaning
99-
3. For each lab value, use "status" field with values "normal", "high", or "low" based on whether the value falls within, above, or below the normal range
100-
4. Set "isCritical" to true when the value indicates an urgent medical situation. Set it to false for values that are normal or only slightly abnormal.
101-
5. Include a "conclusion" field that provides a brief interpretation of what this value indicates about the patient's health
102-
6. Include a "suggestions" field that provides brief recommendations based on this value
103-
7. IMPORTANT: If reference ranges are missing from the document, add "reference-ranges-missing" to the missingInformation array in metadata, and use standard reference ranges from trusted medical sources to determine the status.
104-
105-
EXTREMELY IMPORTANT FORMATTING INSTRUCTIONS:
106-
1. ABSOLUTELY DO NOT START YOUR RESPONSE WITH ANY TEXT. Begin immediately with the JSON object.
107-
2. Return ONLY the JSON object without any introduction, explanation, or text like "This appears to be a medical report..."
108-
3. Do NOT include phrases like "Here is the information" or "formatted in the requested JSON structure"
109-
4. Do NOT write any text before the opening brace { or after the closing brace }
110-
5. Do NOT wrap the JSON in code blocks or add comments
111-
6. Do NOT nest JSON inside other JSON fields
112-
7. Start your response with the opening brace { and end with the closing brace }
113-
8. CRITICAL: Do NOT place JSON data inside a definition field or any other field. Return only the direct JSON format requested.
114-
9. Do NOT put explanatory text about how you structured the analysis inside the JSON.
115-
10. Always provide empty arrays ([]) rather than null for empty fields.
116-
11. YOU MUST NOT create a "term" called "Here is the information extracted" or similar phrases.
117-
12. NEVER put actual data inside a "definition" field of a medical term.
118-
119-
YOU REPEATEDLY MAKE THESE MISTAKES:
120-
- You create a "term" field with text like "Here is the information extracted"
121-
- You start your response with "This appears to be a medical report..."
122-
- You write "Here is the information extracted in the requested JSON format:" before the JSON
123-
- THESE ARE WRONG and cause our system to fail
124-
125-
INCORRECT RESPONSE FORMATS (DO NOT DO THESE):
126-
127-
1) DO NOT DO THIS - Adding explanatory text before JSON:
128-
"This appears to be a medical report. Here is the information extracted in the requested JSON format:
129-
130-
{
131-
\"category\": \"heart\",
132-
...
133-
}"
134-
135-
2) DO NOT DO THIS - Nested JSON:
136-
{
137-
"labValues": [
138-
{
139-
"name": "Here is the information extracted",
140-
"value": "{\"labValues\": [{\"name\": \"RBC\", \"value\": \"14.2\"}]}"
141-
}
142-
]
143-
}
144-
145-
CORRECT FORMAT (DO THIS):
146-
{
147-
"title": "Complete Blood Count Results",
148-
"category": "heart",
149-
"labValues": [
150-
{
151-
"name": "Hemoglobin",
152-
"value": "14.2",
153-
"unit": "g/dL",
154-
"normalRange": "13.5-17.5",
155-
"status": "normal",
156-
"isCritical": false,
157-
"conclusion": "Normal hemoglobin levels indicate adequate oxygen-carrying capacity.",
158-
"suggestions": "Continue regular health maintenance."
159-
}
160-
],
161-
"diagnoses": [...],
162-
"metadata": {...}
163-
}
164-
165-
If any information is not visible or unclear in the document, list those items in the missingInformation array.
166-
Ensure all visible medical terms are explained in plain language. Mark lab values as abnormal if they fall outside the normal range.
71+
For lab values:
72+
- Set "isCritical" to true for urgent medical situations
73+
- Provide brief "conclusion" about what the value means for health
74+
- Add brief "suggestions" based on the value
75+
- If reference ranges are missing, add "reference-ranges-missing" to missingInformation and use standard ranges
76+
77+
CRITICAL FORMATTING RULES:
78+
- Begin immediately with { and end with }
79+
- No text before/after the JSON
80+
- No introduction, explanations, code blocks, or comments
81+
- No nested JSON or definition fields
82+
- Empty arrays ([]) for null fields
83+
- No "term" fields with phrases like "Here is the information extracted"
84+
85+
Common errors to avoid:
86+
- Adding explanatory text before JSON
87+
- Starting with "This appears to be a medical report..."
88+
- Creating nested JSON structures
89+
- Placing data inside definition fields
16790
16891
Document text:
16992
`;

backend/src/reports/reports.service.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -376,21 +376,51 @@ export class ReportsService {
376376
}
377377

378378
try {
379+
// First check if the report exists and belongs to the user
380+
await this.findOne(report.id, report.userId);
381+
382+
// Set the updatedAt timestamp
383+
report.updatedAt = new Date().toISOString();
384+
379385
// Update report in DynamoDB
380-
const command = new PutItemCommand({
386+
const command = new UpdateItemCommand({
381387
TableName: this.tableName,
382-
Item: marshall(report),
383-
ConditionExpression: 'userId = :userId',
388+
Key: marshall({
389+
userId: report.userId, // Partition key
390+
id: report.id, // Sort key
391+
}),
392+
UpdateExpression:
393+
'SET title = :title, bookmarked = :bookmarked, category = :category, ' +
394+
'processingStatus = :processingStatus, labValues = :labValues, summary = :summary, ' +
395+
'confidence = :confidence, status = :status, updatedAt = :updatedAt',
396+
ConditionExpression: 'userId = :userId', // Ensure the report belongs to the user
384397
ExpressionAttributeValues: marshall({
398+
':title': report.title,
399+
':bookmarked': report.bookmarked,
400+
':category': report.category,
401+
':processingStatus': report.processingStatus,
402+
':labValues': report.labValues,
403+
':summary': report.summary,
404+
':confidence': report.confidence,
405+
':status': report.status,
406+
':updatedAt': report.updatedAt,
385407
':userId': report.userId,
386408
}),
409+
ReturnValues: 'ALL_NEW',
387410
});
388411

389-
await this.dynamoClient.send(command);
390-
this.logger.log(`Successfully updated report with ID ${report.id}`);
412+
const response = await this.dynamoClient.send(command);
391413

392-
return report;
414+
if (!response.Attributes) {
415+
return report; // Return the updated report if no Attributes returned
416+
}
417+
418+
return unmarshall(response.Attributes) as Report;
393419
} catch (error: unknown) {
420+
if (error instanceof NotFoundException) {
421+
throw error;
422+
}
423+
394424
this.logger.error(`Error updating report with ID ${report.id}:`);
395425
this.logger.error(error);
396426

0 commit comments

Comments
 (0)