clinicpal / src /app /api /analyze /test /route.ts
Vrda's picture
Deploy ClinIcPal frontend
9bc2f29 verified
import { NextResponse } from 'next/server';
import { getSystemPrompt, generateCompletion } from '@/lib/ollama';
import type { ErrorCategory } from '@/types';
// Sample clinical note for testing prompts
const TEST_CLINICAL_NOTE = `Patient: John Smith, 65M
Chief Complaint: Chest pain
Vital Signs:
- BP: 145/92 mmHg
- HR: 88 bpm
- Temp: 98.6°F
Current Medications:
- Metoprolol 50mg daily
- Aspirin 81mg daily
Assessment: Patient presents with stable angina. Continue current medications.`;
interface TestPromptRequest {
prompt: string;
model: string;
}
// POST /api/analyze/test - Test a custom prompt
export async function POST(request: Request) {
try {
const body: TestPromptRequest = await request.json();
// Validate request
if (!body.prompt || body.prompt.trim().length === 0) {
return NextResponse.json(
{
success: false,
error: 'Prompt is required',
},
{ status: 400 }
);
}
if (!body.model) {
return NextResponse.json(
{
success: false,
error: 'Model selection is required',
},
{ status: 400 }
);
}
// Build the full system prompt with protected JSON format
const allCategories: ErrorCategory[] = [
'medication',
'measurement',
'logical',
'missing',
'terminology',
];
const systemPrompt = getSystemPrompt(allCategories, body.prompt);
// Test the prompt with a simple clinical note
const response = await generateCompletion({
model: body.model,
prompt: `Analyze the following clinical note for documentation errors. Respond with ONLY valid JSON, no additional text or markdown formatting.
=== CLINICAL NOTE START ===
${TEST_CLINICAL_NOTE}
=== CLINICAL NOTE END ===`,
system: systemPrompt,
options: {
temperature: 0.1,
num_predict: 1024,
},
});
// Try to parse the response as JSON to validate format
let parsed;
try {
parsed = JSON.parse(response.response);
} catch {
// Try extracting from markdown code block
const codeBlockMatch = response.response.match(/```(?:json)?\s*([\s\S]*?)```/);
if (codeBlockMatch) {
try {
parsed = JSON.parse(codeBlockMatch[1].trim());
} catch {
const jsonMatch = response.response.match(/\{[\s\S]*\}/);
if (jsonMatch) {
parsed = JSON.parse(jsonMatch[0]);
} else {
throw new Error('Response is not valid JSON');
}
}
} else {
const jsonMatch = response.response.match(/\{[\s\S]*\}/);
if (jsonMatch) {
parsed = JSON.parse(jsonMatch[0]);
} else {
throw new Error('Response is not valid JSON');
}
}
}
// Validate the structure
if (!parsed || typeof parsed !== 'object') {
return NextResponse.json(
{
success: false,
error: 'Response is not a valid JSON object',
},
{ status: 400 }
);
}
if (!Array.isArray(parsed.errors)) {
return NextResponse.json(
{
success: false,
error: 'Response missing "errors" array',
},
{ status: 400 }
);
}
if (!parsed.summary || typeof parsed.summary !== 'object') {
return NextResponse.json(
{
success: false,
error: 'Response missing "summary" object',
},
{ status: 400 }
);
}
return NextResponse.json({
success: true,
data: {
errorsFound: parsed.errors.length,
sampleResponse: parsed,
},
});
} catch (error) {
const message = error instanceof Error ? error.message : 'Test failed';
if (message.includes('timeout') || message.includes('Timeout')) {
return NextResponse.json(
{
success: false,
error: 'Test timed out. Try a simpler prompt.',
},
{ status: 504 }
);
}
if (message.includes('connect') || message.includes('Connection')) {
return NextResponse.json(
{
success: false,
error: 'Cannot connect to Ollama server.',
},
{ status: 503 }
);
}
return NextResponse.json(
{
success: false,
error: message,
},
{ status: 500 }
);
}
}