Saltar al contenido principal

Manejo de errores

Códigos de error HTTP

CódigoSignificadoCausa comúnAcción recomendada
400Bad RequestFalta el campo requerido medical_note o formato de petición inválidoAsegurar que el campo medical_note está proporcionado (requerido)
401UnauthorizedToken inválido o expiradoVerifique su token Bearer y que esté activo
413Payload Too Largemedical_note excede 50KB o pdf_file excede 5MB decodificadoReducir tamaño de entrada o dividir contenido
422Unprocessable EntityEstructura PDF inválida, datos base64 malformados, mime_type inválidoValidar estructura y codificación del archivo PDF
429Too Many RequestsLímite de velocidad excedidoEspera y reintenta con backoff exponencial
500Internal Server ErrorError inesperado del servidor, problemas de base de datos, mala configuraciónReintenta con backoff exponencial; si persiste, reporta el run_id
503Service UnavailableServicio de IA temporalmente no disponibleReintenta después de unos segundos
504Gateway TimeoutLa petición excedió el límite de procesamiento de 10 minutosReducir tamaño de entrada o dividir contenido

Formato de respuestas de error

Todos los errores siguen esta estructura consistente:
{
  "success": false,
  "error": "Bad Request",
  "details": "medical_note es requerido"
}

Campos de error

CampoDescripción
successSiempre false para respuestas de error
errorNombre/tipo de error (ej: “Bad Request”, “Unauthorized”)
detailsMensaje de error detallado explicando qué salió mal

Estrategia de reintentos

¿Cuándo reintentar?

Sí, reintentar:
  • Errores 5xx (500, 502, 503, 504)
  • Error 429 (Too Many Requests)
  • Errores de red/timeout
No reintentar:
  • Errores 4xx excepto 429 (son errores de cliente)
  • Error 401 (token inválido)
  • Error 422 (esquema inválido)

Backoff exponencial

Intento 1: inmediato
Intento 2: espera 1 segundo
Intento 3: espera 2 segundos
Intento 4: espera 4 segundos
Intento 5: espera 8 segundos
...

Implementación en Python

import time
import requests
from requests.exceptions import RequestException

def codify_with_retry(payload, max_retries=3):
    """Llama a la API Codify con reintentos exponenciales"""
    url = "https://{tu-endpoint}/v1/codify"
    headers = {
        "Authorization": "Bearer TU_TOKEN",
        "Content-Type": "application/json"
    }
    
    for attempt in range(max_retries):
        try:
            response = requests.post(
                url=url,
                json=payload,
                headers=headers,
                timeout=600  # Timeout de 10 minutos para Codify
            )
            
            # Si es 429 o 5xx, reintentar
            if response.status_code in [429, 500, 502, 503, 504]:
                if attempt < max_retries - 1:
                    wait_time = 2 ** attempt
                    print(f"⏳ Reintentando en {wait_time}s...")
                    time.sleep(wait_time)
                    continue
            
            # Para otros errores, lanzar excepción
            response.raise_for_status()
            return response.json()
            
        except RequestException as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt
                print(f"⏳ Error de red, reintentando en {wait_time}s...")
                time.sleep(wait_time)
            else:
                raise
    
    raise Exception("Máximo de reintentos alcanzado")

# Uso
try:
    result = codify_with_retry({
        "medical_note": "Paciente con Diabetes tipo 2...",
        "model": "balanced"
    })
    print(f"Éxito! Códigos: {len(result['final_code_assessments'])}")
except Exception as e:
    print(f"Error: {e}")

Implementación en JavaScript

async function codifyWithRetry(payload, maxRetries = 3) {
  const url = 'https://{tu-endpoint}/v1/codify';
  const headers = {
    'Authorization': 'Bearer TU_TOKEN',
    'Content-Type': 'application/json'
  };
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await axios.post(url, payload, {
        headers,
        timeout: 600000  // Timeout de 10 minutos para Codify
      });
      
      return response.data;
      
    } catch (error) {
      const status = error.response?.status;
      
      // Reintentar en 429 y 5xx
      if ([429, 500, 502, 503, 504].includes(status)) {
        if (attempt < maxRetries - 1) {
          const waitTime = Math.pow(2, attempt) * 1000;
          console.log(`⏳ Reintentando en ${waitTime/1000}s...`);
          await new Promise(resolve => setTimeout(resolve, waitTime));
          continue;
        }
      }
      
      // Para otros errores, lanzar
      throw error;
    }
  }
  
  throw new Error('Máximo de reintentos alcanzado');
}

// Uso
try {
  const result = await codifyWithRetry({
    medical_note: 'Paciente con Diabetes tipo 2...',
    model: 'balanced'
  });
  console.log(`Éxito! Códigos: ${result.final_code_assessments.length}`);
} catch (error) {
  console.error('Error:', error.response?.data || error.message);
}

Seguimiento y auditoría

Uso de run_id para depuración

Cada respuesta incluye un run_id único que debe almacenar para seguimiento y depuración:
def save_codification_result(patient_id, result):
    """Guardar resultado de codificación con run_id para seguimiento"""
    database.insert({
        'patient_id': patient_id,
        'run_id': result['run_id'],
        'codes': result['final_code_assessments'],
        'discarded_codes': result['discarded_code_assessments'],
        'timestamp': datetime.now(),
        'processed': True
    })
    
    print(f"✅ Codificación guardada (run_id: {result['run_id']})")
    return result['run_id']

# Uso
result = codify_with_retry({"medical_note": "..."})
run_id = save_codification_result("pt_456", result)

Deduplicación por hash de contenido

Para evitar procesar la misma nota múltiples veces, use hash de contenido:
import hashlib
import json

def get_content_hash(medical_note):
    """Generar hash del contenido de la nota médica"""
    return hashlib.sha256(medical_note.encode()).hexdigest()

def codify_with_deduplication(medical_note):
    """Procesar nota solo si no ha sido procesada anteriormente"""
    content_hash = get_content_hash(medical_note)
    
    # Verificar si ya se procesó
    existing = database.query(
        "SELECT * FROM codifications WHERE content_hash = ?",
        content_hash
    )
    
    if existing:
        print(f"✅ Ya procesado (run_id: {existing['run_id']})")
        return existing['result']
    
    # Procesar nueva nota
    result = codify_with_retry({"medical_note": medical_note})
    
    # Guardar con hash
    database.insert({
        'content_hash': content_hash,
        'run_id': result['run_id'],
        'result': json.dumps(result),
        'processed_at': datetime.now()
    })
    
    return result

Headers opcionales de seguimiento

Use los headers doctor y patient para mejorar las pistas de auditoría:
def codify_with_tracking(medical_note, doctor_id, patient_id):
    """Codificar con información completa de seguimiento"""
    url = "https://{tu-endpoint}/v1/codify"
    headers = {
        "Authorization": "Bearer TU_TOKEN",
        "Content-Type": "application/json",
        "x-doctor": doctor_id,
        "x-patient": patient_id
    }
    
    payload = {"medical_note": medical_note}
    
    response = requests.post(url, json=payload, headers=headers)
    result = response.json()
    
    # Registrar con contexto completo
    logger.info(f"Nota codificada para paciente {patient_id} por doctor {doctor_id}, run_id: {result['run_id']}")
    
    return result

Próximos pasos