Skip to main content

Cloud Functions (OCR & Facial Recognition)

Este documento describe 7 Cloud Functions creadas en Node.js.  
Se dividen en **Funciones de OCR** y **Funciones de Reconocimiento Facial** para su mejor entendimiento.

---

## Índice

1. **Funciones de OCR**  
   - [ocrReadAndWriteImage](#1-ocrreadandwriteimage)  
   - [saveMinimalBotConversations](#2-saveminimalbotconversations)  
   - [sendOCRdataToCreatePerson](#3-sendocrdatatocreateperson)

2. **Funciones de Reconocimiento Facial**  
   - [createPerson](#4-createperson)  
   - [facialRecognition](#5-facialrecognition)  
   - [searchPersonInDB](#6-searchpersonindb)  
   - [verifyPersonIdentity](#7-verifypersonidentity)

---

## Funciones de OCR

### 1. **ocrReadAndWriteImage**

**Endpoint** : https://us-west1-servicios-350819.cloudfunctions.net/ocrReadAndWriteImage

**Función Exportada**  
```js
functions.http('processImage', async (req, res) => { ... })
```

#### Descripción

Esta función recibe la **URL de una imagen**, la procesa usando **Google Generative AI** para extraer datos de identificación en un formato JSON y los **normaliza** (ajusta campos como `name` → `first_name` y `last_name`, direcciones, fechas, etc.).  
Finalmente, envía el JSON normalizado a la ruta configurada en `CONFIG.RECEIVER_URL`.

#### Flujo Principal

1. **Obtener la URL** de la imagen (por `req.query.url` o `req.body.url`).
2. **Descargar** la imagen y convertirla a Base64.
3. **Invocar** el modelo generativo (por ejemplo, `"gemini-1.5-flash"`).
4. **Limpiar** y **parsear** la respuesta para extraer el JSON.
5. **Normalizar** campos (separar `first_name`, `last_name`, unificar direcciones, etc.).
6. **Enviar** el JSON resultante a la función receptora (por POST).
7. **Retornar** el JSON normalizado al cliente.

#### Parámetros de Entrada

- **Body JSON** (o Query Params):
    
    - `url` _(string, requerido)_: URL de la imagen a procesar.

**Ejemplo Body:**

```JSON
{
  "url": "https://example.com/my-id-image.jpg"
}
```
- No requiere otros campos. Si se omite `url`, retorna error 400.
#### Respuesta

- **200 OK**  
    Devuelve un objeto JSON con los campos extraídos y normalizados:

```JSON
{
  "first_name": "Jane",
  "last_name": "Smith",
  "driver_license_number": "ABC12345",
  "date_of_birth": "1992-02-02",
  "expiration_date": "2032-02-02",
  ...
}
```

- **400 Bad Request**  
    Si no se proporciona `url`.
- **422 Unprocessable Entity**  
    Si la respuesta de la AI no es un JSON válido.
- **500 Internal Server Error**  
    Cualquier otro error en el procesamiento o en la llamada a la función receptora.

#### Dependencias

- **@google-cloud/functions-framework** (para exponer la función como HTTP).
- **node-fetch** (para descargar la imagen y enviar datos).
- **@google/generative-ai** (cliente de Google Generative AI).
- **dotenv** (para leer variables de entorno como `API_KEY`, `PROMPT`, etc.).

#### Variables de Entorno

- `API_KEY` — Clave para Google Generative AI.
- `PROMPT` — Texto base para el modelo.
- `RECEIVER_URL` — URL destino donde se envía el JSON resultante.
- `MODEL_NAME` — Nombre del modelo a usar (por defecto `"gemini-1.5-flash"`).

_______________________________________________________________________

### 2. **saveMinimalBotConversations**

**Endpoint** : https://us-central1-servicios-350819.cloudfunctions.net/saveMinimalBotConversations

**Función Exportada**
```js
functions.http('sendDataToGoogleSheet', async (req, res) => { ... })
```

#### Descripción

Esta función toma datos relacionados con OCR (o similar) y los **almacena** en Google Sheets mediante el servicio de **SheetDB**:

1. Determina **en qué hoja** (sheet) colocar la información según si los datos están en **español** (`data.nombre`) o **inglés** (`data.first_name`).
2. Construye el objeto `sheetData` (con `sheet` y `data`) y realiza una llamada `POST` a la URL de SheetDB (`API_URL`).
3. Retorna al cliente la respuesta de la API de SheetDB.

#### Parámetros de Entrada

- **Body JSON** (requerido):
    - `nombre` _(string, opcional)_: si existe, se guardará en la hoja "OCR Esp".
    - `first_name` _(string, opcional)_: si existe, se guardará en la hoja "OCR Eng".
    - Otros campos libres (apellidos, dirección, etc.) también se guardan.
    
**Ejemplo Body en Español:**

```JSON
{
  "nombre": "Juan Perez",
  "fecha_nacimiento": "1985-01-01",
  "direccion": "Av. Principal 123"
}
```

**Ejemplo Body en Inglés:

```JSON
{
  "first_name": "John",
  "last_name": "Doe",
  "date_of_birth": "1990-05-15"
}
```

- **Importante**: Debe existir **al menos** `nombre` **o** `first_name`. De lo contrario, responde `400 JSON format not recognized`.

#### Respuesta

- **200 OK**  
    Devuelve el resultado de la API de SheetDB:
    
```JSON
{
  "first_name": "John",
  "last_name": "Doe",
  "date_of_birth": "1990-05-15"
}
```

- **400 Bad Request**  
    Si no encuentra ni `nombre` ni `first_name`.
- **500 Internal Server Error**  
    Cualquier otro error interno o fallo en la llamada a SheetDB.

#### Flujo Principal

1. **Validar** que la petición sea `POST`.
2. **Leer** el objeto `data` del `body` de la petición.
3. **Definir** la hoja destino (`"OCR Esp"` si se detecta `nombre`, `"OCR Eng"` si se detecta `first_name`).
4. **Enviar** los datos a la API de SheetDB.
5. **Retornar** la respuesta de la API.

#### Dependencias

- **@google-cloud/functions-framework**
- **axios**

#### Consideraciones

- Si no se detectan `nombre` o `first_name`, se responde con `400 JSON format not recognized`.
- El endpoint de SheetDB se encuentra en la variable `API_URL` (en el código).

_______________________________________________________________________

### 3. **sendOCRdataToCreatePerson**

**Endpoint** : https://us-central1-servicios-350819.cloudfunctions.net/sendOCRdataToCreatePerson

**Función Exportada**
```js
functions.http('processImages', async (req, res) => { ... })
```

#### Descripción

Orquesta el **flujo OCR → creación de persona**:

1. Recibe **dos URLs**: `idImageUrl` (imagen de identificación) y `selfieUrl`.
2. Llama a la función **ocrReadAndWriteImage** con la imagen de identificación.
3. **Normaliza** y **transforma** los datos recibidos del OCR para ajustarlos a la estructura que requiere **createPerson**.
4. Invoca **createPerson** con esos datos y la `selfieUrl`.
5. Retorna la respuesta de `createPerson` y los datos enviados (sin la URL de la selfie).

#### Parámetros de Entrada

- **Body JSON** (o Query Params):
    
    - `idImageUrl` _(string, requerido)_: URL de la imagen de la identificación.
    - `selfieUrl` _(string, requerido)_: URL de la imagen tipo selfie.
    
**Ejemplo Body**

```JSON
{
  "idImageUrl": "https://example.com/my-id.jpg",
  "selfieUrl": "https://example.com/my-selfie.jpg"
}
```
- Si faltan `idImageUrl` o `selfieUrl`, retorna `400`.

#### Respuesta
- **200 OK**
```JSON
{
  "response": {
    "message": "Person Created Successfully",
    "supabase_id": 123
  },
  "savedData": {
    "name": "Juan Perez",
    "date_of_birth": "1985-01-01",
    "gender": "M"
    ...
  }
}
```
- **400 Bad Request**  
    Si faltan URLs en los parámetros.
- **500 Internal Server Error**  
    Cualquier error al procesar la OCR o la creación de persona.

#### Flujo Principal

1. **Validar** que existan `idImageUrl` y `selfieUrl`.
2. **Invocar** `ocrReadAndWriteImage`, obteniendo los datos OCR.
3. **Formatear** la respuesta OCR (INE vs Licencia, etc.).
4. **Llamar** a `createPerson` con el objeto resultante.
5. **Retornar** la respuesta de creación y los datos utilizados.

#### Dependencias

- **@google-cloud/functions-framework**
- **axios**

#### Funciones Auxiliares

- `formatPersonData(ocrData, selfieUrl)`: Combina campos para ajustarlos al formato requerido por `createPerson`.
- `formatDate(dateString)`: Formatea fechas `DD/MM/YYYY` a `YYYY-MM-DD`.

_______________________________________________________________________
## Funciones de Reconocimiento Facial

### Consideraciones:
- Un "match" corresponde a un puntaje de 0.7 o superior para considerar que las selfies de la o las personas coinciden y se trata de la misma.
- Para mayor referencia revisar la documentación oficial de openCV: 
```cardlink
url: https://us.opencv.fr/docs#/
title: "OpenCV Face Recognition - Swagger UI"
host: us.opencv.fr
```
- Los ids que proporciona openCV son el formato uuid y los ids proporcionados por supase son int8.

### 4. **createPerson**

**Endpoint** : https://us-central1-servicios-350819.cloudfunctions.net/createPerson

**Función Exportada**
```js
functions.http('createPerson', async (req, res) => { ... })
```

#### Descripción

Crea un registro de persona en la base de datos de **OpenCV** y luego **almacena** el `opencv_id` en **Supabase**:

1. Convierte la imagen a Base64.
2. Llama a `https://us.opencv.fr/person` para crear la persona y obtener un `id` (llamado `opencv_id`).
3. Guarda ese `opencv_id` en la tabla `people` de **Supabase**.
4. Retorna el `id` de Supabase y un mensaje de éxito.

#### Parámetros de Entrada

- **Body JSON** (o Query Params):
    
    - `date_of_birth` _(string, requerido)_: fecha de nacimiento en formato `YYYY-MM-DD` (o similar).
    - `gender` _(string, requerido)_: "M" o "F" (o "H" vs "M" según la convención).
    - `imageUrl` _(string, requerido)_: URL de la foto a enrolar.
    - `name` _(string, requerido)_: nombre completo o nombre de la persona.
    - `nationality` _(string, opcional)_: nacionalidad.

**Ejemplo Body**

```JSON
{
  "date_of_birth": "1990-05-15",
  "gender": "M",
  "imageUrl": "https://example.com/person-face.jpg",
  "name": "John Doe",
  "nationality": "US"
}
```
- Si falta alguno de los campos requeridos, retorna 400.

#### Respuesta

- **200 OK**
```JSON
{
  "message": "Person Created Successfully",
  "supabase_id": 17
}
```
- **400 Bad Request**  
    Si faltan parámetros obligatorios (`date_of_birth`, `gender`, `imageUrl`, `name`).
- **500 Internal Server Error**  
    Cualquier error al comunicarse con OpenCV o Supabase.

#### Flujo Principal

1. **Leer** parámetros obligatorios (`date_of_birth`, `gender`, `imageUrl`, `name`…).
2. **Validar** que existan. Retornar `400` si faltan.
3. **Descargar** la imagen y convertirla a Base64.
4. **Invocar** la API de OpenCV para crear la persona.
5. **Insertar** en Supabase el registro con el `opencv_id` devuelto.
6. **Retornar** el `supabase_id` y un mensaje de confirmación.

#### Dependencias

- **@google-cloud/functions-framework**
- **axios**
- **dotenv** (para leer `OPENCV_API_KEY`, `SUPABASE_API_KEY`, etc.)

#### Variables de Entorno

- `OPENCV_API_KEY` — Clave de la API de OpenCV.
- `SUPABASE_API_KEY` — Clave de la API de Supabase.
- `SUPABASE_URL` — URL base del proyecto Supabase.

_______________________________________________________________________

### 5. **facialRecognition**

**Endpoint** : https://us-central1-servicios-350819.cloudfunctions.net/facialRecognition

**Función Exportada**
```js
functions.http('compareImages', async (req, res) => { ... })
```
#### Descripción

Compara **dos imágenes** (una llamada “gallery” y otra “probe”) usando la API de OpenCV:

1. Recibe sus URLs (`gallery_url` y `probe_url`).
2. Descarga ambas y las transforma a Base64.
3. Llama a `https://us.opencv.fr/compare` con el modo `"ACCURATE"`.
4. Devuelve al cliente la respuesta de la API (score, match, etc.).

#### Parámetros de Entrada

- **Body JSON** (o Query Params):
    
    - `gallery_url` _(string, requerido)_: URL de la imagen de galería.
    - `probe_url` _(string, requerido)_: URL de la imagen a comparar.

**Ejemplo Body**

```JSON
{
  "gallery_url": "https://example.com/gallery.jpg",
  "probe_url": "https://example.com/probe.jpg"
}
```
#### Respuesta

- **200 OK**  
    Devuelve el objeto JSON directamente desde la API de OpenCV, por ejemplo:
```JSON
{
  "match": {
    "score": 0.87,
    "bounding_box": ...
    ...
  },
  "status": "success"
}
```
- **400 Bad Request**  
    Si faltan `gallery_url` o `probe_url`.
- **500 Internal Server Error**  
    Si hay un error en la llamada a OpenCV.

#### Flujo Principal

1. **Verificar** la existencia de `gallery_url` y `probe_url`.
2. **Descargar** ambas imágenes en formato binario.
3. **Convertir** a Base64.
4. **Enviar** a la API `compare` de OpenCV.
5. **Retornar** la respuesta completa de OpenCV al cliente.

#### Dependencias

- **@google-cloud/functions-framework**
- **axios**
- **dotenv**

#### Variables de Entorno

- `OPENCV_API_KEY` — Clave para la API de OpenCV.

_______________________________________________________________________

### 6. **searchPersonInDB**

**Endpoint** : https://us-central1-servicios-350819.cloudfunctions.net/searchPersonInDB

**Función Exportada**
```js
functions.http('searchImage', async (req, res) => { ... })
```

#### Descripción

Busca posibles coincidencias de una persona en la base de **OpenCV** a partir de la **imagen** recibida:

1. Recibe la URL de la imagen (`imageUrl`).
2. Convierte la imagen a Base64.
3. Llama a `https://us.opencv.fr/search` especificando un `max_results` y un `min_score`.
4. Retorna la lista de coincidencias que OpenCV considere válidas.

#### Parámetros de Entrada

- **Body JSON** (o Query Params):
    
    - `url` _(string, requerido)_: URL de la imagen a buscar  
        (en el código, también se admite `req.body.imageUrl`).
 
**Ejemplo Body**

```JSON
{
  "url": "https://example.com/face_to_search.jpg"
}
```
- Si falta la URL, retorna 400.
#### Respuesta

- **200 OK**
```JSON
[
  {
    "id": "123",
    "score": 0.92
  },
  {
    "id": "456",
    "score": 0.85
  }
]
```
- **400 Bad Request**  
    Si no se proporciona la URL de la imagen.
- **500 Internal Server Error**  
    Si ocurre un error al llamar a OpenCV o procesar la imagen.

#### Flujo Principal

1. **Validar** que `imageUrl` exista (req.body o req.query).
2. **Descargar** y **codificar** la imagen.
3. **Enviar** la petición a `search` en OpenCV.
4. **Retornar** los resultados.

#### Dependencias

- **@google-cloud/functions-framework**
- **axios**
- **dotenv**

#### Variables de Entorno

- `OPENCV_API_KEY` — Clave para la API de OpenCV.

_______________________________________________________________________

### 7. **verifyPersonIdentity**

**Endpoint** : https://us-central1-servicios-350819.cloudfunctions.net/verifyPersonIdentity

**Función Exportada**

```js
functions.http('verifyFace', async (req, res) => { ... })
```

#### Descripción

Verifica la identidad de una persona comparando una **selfie** con el registro previo en OpenCV:

1. Recibe el `id` (de Supabase) y una `imageUrl`.
2. Busca en la tabla `people` de Supabase para obtener el `opencv_id`.
3. Llama a `https://us.opencv.fr/verify` con la imagen y el `opencv_id`.
4. Retorna el `score` de similitud y el `name` registrado.

#### Parámetros de Entrada

- **Body JSON** (o Query Params):
    
    - `id` _(number, requerido)_: ID de la persona en Supabase (campo `id` de la tabla `people`).
    - `imageUrl` _(string, requerido)_: URL de la selfie a comparar.

**Ejemplo Body**

```JSON
{
  "id": 42,
  "imageUrl": "https://example.com/selfie.jpg"
}
```
#### Respuesta

- **200 OK**
```JSON
{
  "score": 0.85,
  "name": "John Doe"
}
```

- **400 Bad Request**  
    Si faltan `id` o `imageUrl`, o la imagen no se pudo descargar.
- **404 Not Found**  
    Si la persona con ese `id` no existe en Supabase.
- **500 Internal Server Error**  
    Si hay un problema interno (llamadas a OpenCV o a Supabase fallidas).

#### Flujo Principal

1. **Validar** parámetros: `id` y `imageUrl`.
2. **Descargar** la imagen y convertirla a Base64.
3. **Consultar** en Supabase para obtener `opencv_id` y `name`.
4. **Invocar** la API `verify` en OpenCV con el `opencv_id`.
5. **Retornar** `score` y `name`.

#### Dependencias

- **@google-cloud/functions-framework**
- **axios**
- **dotenv**

#### Variables de Entorno

- `OPENCV_API_KEY` — Clave para la API de OpenCV.
- `SUPABASE_API_KEY` — Clave para la API de Supabase.