Spaces:
Running
Running
| 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"; | |
| () | |
| export class OcrService { | |
| constructor( | |
| private readonly cloudinary: CloudinaryService, | |
| private readonly groqVision: GroqVisionProvider, | |
| private readonly patientsService: PatientsService, | |
| ) {} | |
| async extractPatientRecord(files: Express.Multer.File[]): Promise<OcrServiceResponse> { | |
| /** | |
| * 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, | |
| }; | |
| } | |
| } |