File size: 2,715 Bytes
27e706d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2f2357a
27e706d
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101



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<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,
    };
  }
}