import { Injectable } from "@nestjs/common"; import { CloudinaryService } from "./cloudinary.service"; import { GroqVisionProvider } from "./providers/groq-vision-provider"; import { validatePatient } from "./validators/patient.validator"; import { PatientsService } from "../patients/patients.service"; import type { OcrServiceResponse } from "./validators/types"; @Injectable() export class OcrService { constructor( private readonly cloudinary: CloudinaryService, private readonly groqVision: GroqVisionProvider, private readonly patientsService: PatientsService, ) {} async extractPatientRecord(files: Express.Multer.File[]): Promise { /** * 1 Upload images */ const uploadedImages = await Promise.all( files.map((file) => this.cloudinary.uploadImage(file)), ); /** * 2 Collect URLs */ const imageUrls = uploadedImages.map((img) => img.secure_url); /** * 3 OCR */ const extracted = await this.groqVision.extractPatientRecord(imageUrls); /** * 4 Validate */ const validated = validatePatient(extracted); /** * 5 Check for missing required fields */ const missingFields: string[] = []; const requiredFields = [ "firstName", "lastName", "gestationalAge", "phone", "age", ]; requiredFields.forEach((field) => { const fieldValue = validated.data[field as keyof typeof validated.data]; if (!fieldValue || (fieldValue as any).value === null || (fieldValue as any).value === undefined) { missingFields.push(field); validated.warnings.push({ field, message: `${field} was not detected.`, severity: "warning", }); } }); /** * 6 Check for duplicates */ let duplicatePatient = false; let existingPatientId: string | undefined = undefined; if (!missingFields.includes("phone") && !missingFields.includes("firstName") && !missingFields.includes("lastName")) { const duplicate = await this.patientsService.findDuplicatePatient({ phone: (validated.data.phone?.value) ?? undefined, firstName: (validated.data.firstName?.value) ?? undefined, lastName: (validated.data.lastName?.value) ?? undefined, }); if (duplicate) { duplicatePatient = true; existingPatientId = duplicate.id; } } /** * 7 Return response */ return { images: imageUrls, extracted: validated.data, warnings: validated.warnings, missingFields, duplicatePatient, existingPatientId, validationSummary: validated.summary, }; } }