openapi: 3.0.1
info:
  version: 3.2.0
  title: API REST de Voice-Service
  description: |
    API REST de la solución biométrica para el enrolamiento y la autenticación de voz.

    La autenticación JWT opcional puede habilitarse en el arranque desde `config.json` o mediante las variables de entorno `FACEPHI_VOICE_REST_AUTH_*`.
    Cuando está habilitada, `GET /api/v1/version` y `GET /api/v1/health` siguen siendo públicos mientras que el resto de los endpoints requieren un JWT válido.

servers:
 - url: http://127.0.0.1:6982/

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: Nombre por defecto de la cabecera de la API key. Puede sobrescribirse en el arranque con `auth_api_key_header_name`.

  schemas:

    AudioBuffer:
      type: string
      example: /9j/4AAQSkZJRgABAQEAtAC0AAD...
      description: Buffer de audio en bruto en formato WAV, OPUS/OGG, MP3 o AAC, codificado en base64 RFC4648. El audio puede estar cifrado o no.

    AudioTemplate:
      type: string
      example: BAEBGgEroySjGz2C9iIki35J/FA...
      description: Buffer de la plantilla biométrica (template), obtenido de Enrollment(), cifrado y codificado en base64 RFC4648.

    CheckLiveness:
      type: boolean
      default: false
      example: false
      description: Si es true, se realizará una prueba de vida (liveness)

    CheckQuality:
      type: boolean
      default: true
      example: true
      description: Si es true, se realizará una comprobación de calidad

    LivenessThreshold:
      type: number
      default: 0.5
      example: 0.5
      description: Umbral para la detección de vida (liveness). Si la probabilidad de vida es inferior a este valor, el audio se considera inválido.

    OperationResult:
      type: number
      description: Resultado de la operación.
      example: 3
      enum:
        - NOISY                          = 0
        - LONG_REVERBERATION             = 1
        - SMALL_SPEECH                   = 2
        - OK                             = 3
        - NOT_EVALUATED                  = 4
        - SPOOF                          = 5
        - DUPLICATED_AUDIO               = 6
        - DIFFERENT_VOICES               = 7
        - EMPTY_AUDIO                    = 8
        - TOO_MANY_AUDIOS                = 9
        - NOT_ENOUGH_GOOD_AUDIOS         = 10
        - CONFIG_MANAGER_ERROR           = 11
        - INVALID_LICENSE                = 12
        - EXPIRED                        = 13
        - SUSPENDED                      = 14
        - E_SYSTEM_PERMISSION            = 15
        - E_WMIC                         = 16
        - E_INET                         = 17
        - E_NET_PROXY                    = 18
        - E_REVOKED                      = 19
        - E_LICENSE_KEY                  = 20
        - E_ACTIVATION_LIMIT             = 21
        - E_VM                           = 22
        - E_COUNTRY                      = 23
        - E_IP                           = 24
        - E_CONTAINER                    = 25
        - DATA_NOT_FOUND                 = 26
        - ENVIRONMENT_VARIABLE_NOT_FOUND = 27
        - SMALL_RELATIVE_SPEECH          = 28
        - MULTIPLE_SPEAKERS              = 29

    TemplateType:
      type: string
      description: Tipo de plantilla (template) devuelto como resultado de la operación.
      example: "text-dependent"

    Match:
      type: boolean
      description: Indica si el audio coincide con la plantilla (template)
      example: true

    LivenessScore:
      type: number
      description: Probabilidad de vida (liveness)
      example: 0.9

    MatchingScore:
      type: number
      description: Probabilidad de coincidencia (matching)
      example: 0.9

    AudioPosition:
      type: integer
      description: Posición del audio en el vector de audios. Comienza en 0.
      example: 0

    TimeStamp:
      type: string
      description: Un valor de fecha/hora en formato "%Y-%m-%dT%H:%M:%SZ".
      example: "2022-01-14T10:42:05.521922Z"

    MinimumSnrDb:
      type: number
      description: SNR mínimo en dB para que el audio se considere válido.
      default: 8.0
      example: 8.0

    MinimumAudioLengthMs:
      type: number
      description: Duración mínima del audio en milisegundos para que se considere válido.
      default: 1000.0
      example: 1000.0

    MinimumSpeechRelativeLength:
      type: number
      description: Longitud relativa mínima del habla (longitud del habla en relación con la duración total del audio).
      default: 0.0
      example: 0.0

    MaximumMultipleSpeakersDetectorScore:
      type: number
      description: Puntuación máxima permitida del detector de múltiples hablantes.
      default: 1.0
      example: 1.0

    ExtraData:
      type: string
      description: Datos tokenizados para invocar al servicio Api Tracking tras la operación, codificados en base64.
      example: BQABAQGkJhiCqQjKYUZyDM...

    SnrDbDetected:
      type: number
      description: SNR en dB detectado en el audio.
      example: 8.0

    SpeechLengthMsDetected:
      type: number
      description: Duración del habla en milisegundos detectada en el audio.
      example: 1000.0

    SpeechRelativeLengthDetected:
      type: number
      description: Longitud relativa del habla detectada en el audio.
      example: 0.5

    MultipleSpeakersScoreDetected:
      type: number
      description: Puntuación de múltiples hablantes detectada en el audio.
      example: 1.0

    TrackingStatus:
      type: number
      description: Estado devuelto por el servicio Api Tracking, o -1 si no se requiere tracking.
      example: 201

    TrackingMessage:
      type: string
      description: Mensaje devuelto por el servicio Api Tracking, o vacío si no se requiere tracking.
      example: "Authentication: Ok"

    AudioResult:
      type: object
      description: Resultado del procesamiento de un audio
      properties:
        audio_position:
          $ref: '#/components/schemas/AudioPosition'
        result_code:
          $ref: '#/components/schemas/OperationResult'
        liveness_score:
          $ref: '#/components/schemas/LivenessScore'
        matching_score:
          $ref: '#/components/schemas/MatchingScore'
        snr_db_detected:
          $ref: '#/components/schemas/SnrDbDetected'
        speech_length_ms_detected:
          $ref: '#/components/schemas/SpeechLengthMsDetected'
        speech_relative_length_detected:
          $ref: '#/components/schemas/SpeechRelativeLengthDetected'
        multiple_speakers_score_detected:
          $ref: '#/components/schemas/MultipleSpeakersScoreDetected'


    EnrollmentBody:
      type: object
      description: Cuerpo (body) de la petición de enrollment
      properties:
        audios:
          description: La longitud del array puede ser 1, o de 3 a 5. No es válido enviar 2 audios, ni más de 5.
                       1 audio para enrolamiento text-independent.
                       de 3 a 5 audios para enrolamiento text-dependent.
          type: array
          maxItems: 5
          items:
            $ref: '#/components/schemas/AudioBuffer'
        check_liveness:
          $ref: '#/components/schemas/CheckLiveness'
        check_quality:
          $ref: '#/components/schemas/CheckQuality'
        liveness_threshold:
          $ref: '#/components/schemas/LivenessThreshold'
        minimum_snr_db:
          $ref: '#/components/schemas/MinimumSnrDb'
        minimum_speech_duration_ms:
          $ref: '#/components/schemas/MinimumAudioLengthMs'
        minimum_speech_relative_length:
          $ref: '#/components/schemas/MinimumSpeechRelativeLength'
        maximum_multiple_speakers_detector_score:
          $ref: '#/components/schemas/MaximumMultipleSpeakersDetectorScore'
        extra_data:
          $ref: '#/components/schemas/ExtraData'
      required:
        - audios

    EnrollmentResponse:
      type: object
      description: Respuesta de enrollment
      properties:
        operation_result:
          $ref: '#/components/schemas/OperationResult'
        template_type:
          $ref: '#/components/schemas/TemplateType'
        template:
          $ref: '#/components/schemas/AudioTemplate'
        validate_audios_result:
          type: array
          items:
            $ref: '#/components/schemas/AudioResult'

    AuthenticationBody:
      type: object
      description: Cuerpo (body) de la petición de authentication
      properties:
        audio:
          $ref: '#/components/schemas/AudioBuffer'
        template:
          $ref: '#/components/schemas/AudioTemplate'
        check_liveness:
          $ref: '#/components/schemas/CheckLiveness'
        check_quality:
          $ref: '#/components/schemas/CheckQuality'
        liveness_threshold:
          $ref: '#/components/schemas/LivenessThreshold'
        minimum_snr_db:
          $ref: '#/components/schemas/MinimumSnrDb'
        minimum_speech_duration_ms:
          $ref: '#/components/schemas/MinimumAudioLengthMs'
        minimum_speech_relative_length:
          $ref: '#/components/schemas/MinimumSpeechRelativeLength'
        maximum_multiple_speakers_detector_score:
          $ref: '#/components/schemas/MaximumMultipleSpeakersDetectorScore'
        extra_data:
          $ref: '#/components/schemas/ExtraData'
      required:
        - audio
        - template

    AuthenticationResponse:
      type: object
      description: Respuesta de authentication
      properties:
        operation_result:
          $ref: '#/components/schemas/OperationResult'
        match:
          $ref: '#/components/schemas/Match'
        liveness_score:
          $ref: '#/components/schemas/LivenessScore'
        matching_score:
          $ref: '#/components/schemas/MatchingScore'
        snr_db_detected:
          $ref: '#/components/schemas/SnrDbDetected'
        speech_length_ms_detected:
          $ref: '#/components/schemas/SpeechLengthMsDetected'
        speech_relative_length_detected:
          $ref: '#/components/schemas/SpeechRelativeLengthDetected'
        multiple_speakers_score_detected:
          $ref: '#/components/schemas/MultipleSpeakersScoreDetected'
        tracking_status:
          $ref: '#/components/schemas/TrackingStatus'
        tracking_message:
          $ref: '#/components/schemas/TrackingMessage'

    BadRequestResult:
      type: object
      description: Resultado cuando llegan parámetros incorrectos en la petición.
      properties:
        status:
          type: number
          example: 400
        error:
          type: string
          example: "BadRequest"
        timeStamp:
          $ref: '#/components/schemas/TimeStamp'

    ExceptionResult:
      type: object
      description: Se ha producido un error en la llamada al backend de Voice-SDK.
      properties:
        status:
          type: number
          example: 500
        error:
          type: string
          example: "Voice-SDK Exception"
        exception:
          type: string
          example: "Bad format"
        timeStamp:
          $ref: '#/components/schemas/TimeStamp'

    HealthStatus:
      type: string
      description: Resultado del servicio de salud (health) (indica si el SDK está activo o no).
      example: "Healthy"
      enum:
        - Healthy
        - Unhealthy

    HealthResult:
      type: object
      description: El resultado de una comprobación de salud (health check).
      properties:
        message:
          $ref: '#/components/schemas/HealthStatus'

    VersionResult:
      type: object
      description: El resultado de una comprobación de versión.
      properties:
        message:
          type: string
          example: "2.5.0 Copyright @ 2024 FacePhi. All rights reserved."

    ConfigResult:
      type: object
      description: Objeto Json con los parámetros de configuración del servicio. Los ajustes de autenticación JWT se omiten intencionadamente.
      example: {
        "port": 6982,
        "number_of_threads": 1,
        "connection_timeout": 0,
        "keep_alive_request_number": 0,
        "client_max_body_size": 100,
        "logger_path": "",
        "logger_level": "off",
        "logger_rotation": "daily",
        "logger_max_files": 7
      }

    ConfigBody:
      type: object
      description: Cuerpo (body) de la petición de config. Este endpoint no acepta ajustes de autenticación JWT.
      properties:
        config_json_string:
          type: string
          description: Cadena Json con los parámetros de configuración del servicio que pueden actualizarse en tiempo de ejecución.
          example: "{\"fake_param\":\"fake\",\"number_of_threads\":\"2\"}"
      required:
        - config_json_string

security:
  - BearerAuth: []
  - ApiKeyAuth: []

paths:
  /api/v1/enrollment:
    post:
      description: Este endpoint se utiliza para registrar (enroll) una nueva voz. Recibe uno o varios archivos de audio y devuelve una plantilla de voz (voice template). La plantilla de voz es una cadena que contiene la información biométrica de la voz. Esta plantilla puede utilizarse para autenticar las voces en el futuro.

      tags:
        - Enrollment

      requestBody:
        description: Json con la voz de entrada cifrada y codificada en formato base64 RFC4648
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnrollmentBody'

      responses:
        '200':
          description: El resultado del enrolamiento de voz. Los campos *_detected solo están presentes cuando falla la comprobación de calidad del audio.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnrollmentResponse'

        '400':
          description: Han llegado parámetros incorrectos en la petición.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequestResult'

        '500':
          description: Se ha producido un error en la llamada al backend de Voice-SDK.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExceptionResult'

  /api/v1/authentication:
    post:
      description: Este endpoint se utiliza para autenticar una voz. Recibe un archivo de audio y una plantilla de voz, y devuelve un valor booleano que indica si la voz pertenece a la misma persona que la de la plantilla de voz, así como una probabilidad que indica la similitud entre ambas voces.

      tags:
        - Authentication

      requestBody:
        description: Json con la voz de entrada y la plantilla cifradas y codificadas en formato base64 RFC4648
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthenticationBody'

      responses:
        '200':
          description: El resultado de la autenticación. Los campos *_detected solo están presentes cuando falla la comprobación de calidad del audio.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthenticationResponse'

        '400':
          description: Han llegado parámetros incorrectos en la petición.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequestResult'

        '500':
          description: Se ha producido un error en la llamada al backend de Voice-SDK.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExceptionResult'

  /api/v1/health:
    get:
      description: Comprueba si el servicio está activo.
      security: []

      tags:
        - Management

      responses:
        '200':
          description: Un mensaje con el estado de salud (health).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResult'
        '400':
          description: Han llegado parámetros incorrectos en la petición.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequestResult'
        '500':
          description: Se ha producido un error en la llamada al backend de Voice-SDK.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExceptionResult'

  /api/v1/version:
    get:
      description: Comprueba la versión de Voice Service.
      security: []

      tags:
        - Management

      responses:
        '200':
          description: Un mensaje con la versión.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VersionResult'
        '400':
          description: Han llegado parámetros incorrectos en la petición.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequestResult'
        '500':
          description: Se ha producido un error en la llamada al backend de Voice-SDK.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExceptionResult'

  /api/v1/config:
    get:
      description: Obtiene la configuración del servicio. Los ajustes de autenticación JWT se ocultan intencionadamente en esta respuesta.
      tags:
        - Management
      responses:
        '200':
          description: Objeto Json con la configuración del servicio.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfigResult'
        '400':
          description: Han llegado parámetros incorrectos en la petición.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequestResult'
        '500':
          description: Se ha producido un error en la llamada al backend de Voice-SDK.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExceptionResult'
    post:
      description: Actualiza la configuración del servicio. Solo algunos parámetros pueden actualizarse en tiempo de ejecución.
                   Los parámetros relacionados con la red (port, timeouts, body size...) o el logger (path, level...) no pueden actualizarse en tiempo de ejecución.
                   Los ajustes de autenticación JWT son solo de arranque y este endpoint los rechaza.
      tags:
        - Management
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfigBody'
        required: true
      responses:
        '200':
          description: Mensaje con el resultado de la operación.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: "Configuration updated successfully"

        '400':
          description: Han llegado parámetros incorrectos en la petición.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequestResult'

        '500':
          description: Se ha producido un error en la llamada al backend de Voice-SDK.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExceptionResult'
