Saltar al contenido principal
Esta guía muestra cómo integrar SofIA SDK en aplicaciones React usando el componente <Omniscribe>.

Configuración inicial

1. Instalación

npm install @omniloy/sofia-sdk

2. Importación en su aplicación

import { Omniscribe, LanguageCode } from '@omniloy/sofia-sdk/react';
import '@omniloy/sofia-sdk/react/index.css';

Componente React básico

Implementación con hooks

import { useCallback, useState } from 'react';
import { Omniscribe, LanguageCode } from '@omniloy/sofia-sdk/react';
import '@omniloy/sofia-sdk/react/index.css';

const SofiaComponent = () => {
  const [isOpen, setIsOpen] = useState(true);
  const [lastReport, setLastReport] = useState<unknown>(null);
  const [getLastReportFn, setGetLastReportFn] = useState<(() => Promise<unknown>) | null>(null);

  const handleReport = useCallback((report: unknown) => {
    console.log('Reporte recibido:', report);
    setLastReport(report);
  }, []);

  const handleSetGetLastReport = useCallback((fn: () => Promise<unknown>) => {
    setGetLastReportFn(() => fn);
  }, []);

  const template = {
    title: 'clinical_notes',
    type: 'object',
    properties: {
      diagnosis: {
        type: 'string',
        description: 'Diagnóstico principal',
        source: 'ICD10',
      },
      treatment_plan: {
        type: 'string',
        description: 'Plan de tratamiento discutido durante la consulta',
      },
    },
  };

  return (
    <div>
      <Omniscribe
        baseurl="https://api.example.com/v1"
        wssurl="wss://ws.example.com"
        apikey="sk-your-api-key"
        userid="user_12345"
        patientid="patient_67890"
        templateid="clinical-notes-v1"
        template={template}
        isopen={isOpen}
        setIsOpen={setIsOpen}
        handleReport={handleReport}
        setGetLastReport={handleSetGetLastReport}
        language={LanguageCode.es}
      />

      <button onClick={() => setIsOpen((prev) => !prev)}>
        {isOpen ? 'Cerrar SofIA' : 'Abrir SofIA'}
      </button>

      {lastReport !== null && (
        <pre>{JSON.stringify(lastReport, null, 2)}</pre>
      )}
    </div>
  );
};

export default SofiaComponent;

Props

Requeridas

PropTipoDescripción
baseurlstringEndpoint de la API de SofIA
wssurlstringURL de WebSocket para funciones en tiempo real
apikeystringClave de autenticación
useridstringIdentificador del usuario en el sistema EHR/HIS
patientidstringIdentificador del paciente en el sistema EHR/HIS
templateobjectObjeto de template para la generación de reportes
templateidstringIdentificador del template (ambos template y templateid son necesarios)

Opcionales

PropTipoDescripción
isopenbooleanMostrar/ocultar componente
languageLanguageCodeIdioma de la interfaz (e.g., LanguageCode.es)
debugbooleanHabilitar logging de depuración
patientdataobjectInformación del paciente (ver estructura más abajo)
showconsentindicatorbooleanMuestra el indicador de estado de consentimiento en el encabezado (valor por defecto: false)

Callbacks

PropFirmaDescripción
handleReport(report: unknown) => voidRecibe reportes generados
setIsOpen(value: boolean | (prev: boolean) => boolean) => voidControla visibilidad del widget
setGetLastReport(fn: () => Promise<unknown>) => voidExpone función async para obtener último reporte

Obtener el último reporte

El callback setGetLastReport recibe una función async que puede almacenar y llamar después:
const [getLastReportFn, setGetLastReportFn] = useState<(() => Promise<unknown>) | null>(null);

const handleSetGetLastReport = useCallback((fn: () => Promise<unknown>) => {
  setGetLastReportFn(() => fn);
}, []);

const fetchLastReport = async () => {
  if (getLastReportFn) {
    const report = await getLastReportFn();
    console.log('Último reporte:', report);
  }
};

// En JSX:
<Omniscribe
  setGetLastReport={handleSetGetLastReport}
  // ...otras props
/>

<button onClick={fetchLastReport} disabled={!getLastReportFn}>
  Obtener último reporte
</button>
Pase debug={true} al componente <Omniscribe> para habilitar logging detallado en consola. Esto es útil durante el desarrollo para rastrear eventos del ciclo de vida del SDK, estado de conexión y validación de configuración.
<Omniscribe debug={true} ... />

Actualización de datos del paciente

Use el estado de React para actualizar dinámicamente el contexto del paciente. El SDK se reinicializa automáticamente cuando patientid o userid cambian.
const [patientId, setPatientId] = useState('patient_67890');
const [patientData, setPatientData] = useState({
  fullName: 'Jane Doe',
  birthDate: '15-03-1985',
  phone: '+1 555-987-6543',
  address: '456 Oak Ave, Example City, USA',
  extraData: {
    medical_practice: 'Internal Medicine',
    allergies: 'penicillin',
  },
});

// En JSX:
<Omniscribe
  patientid={patientId}
  patientdata={patientData}
  // ...otras props
/>

// Para cambiar de paciente:
function switchPatient(newId: string, newData: typeof patientData) {
  setPatientId(newId);
  setPatientData(newData);
}

Estructura de datos del paciente

type TPatientData = {
  fullName: string | undefined;
  birthDate: string | undefined;
  phone: string | undefined;
  address: string | undefined;
  extraData: Record<string, unknown> | undefined;
  signedConsent?: { signed: boolean; date: string };
};

Campos de extraData

CampoDescripción
medical_practiceEspecialidad del médico (e.g., "Cardiology", "Pediatrics"). Ayuda a SofIA a contextualizar las respuestas
patient_medical_notesNotas de consultas previas. Incluya campos url para que SofIA pueda citar la fuente
(campos personalizados)Cualquier dato adicional relevante para la consulta (e.g., allergies, medications)

Ejemplo completo

const patientData = {
  fullName: 'John Doe',
  birthDate: '01/15/1980',
  phone: '+1 555-123-4567',
  address: '123 Main St, Example City, USA',
  extraData: {
    medical_practice: 'Cardiology',
    patient_medical_notes: [
      {
        date: '2024-11-20',
        note: 'Patient presents with chest pain. ECG normal. Prescribed aspirin.',
        url: 'https://ehr.example.com/notes/12345',
      },
      {
        date: '2025-01-10',
        note: 'Follow-up visit. Chest pain resolved. Blood pressure 130/85.',
      },
    ],
    allergies: 'pollen, penicillin',
    medications: 'metformin, insulin, aspirin',
  },
  signedConsent: {
    signed: true,
    date: '2025-03-01',
  },
};
Consulta Datos del paciente para la referencia completa de la estructura de datos.

Gestión de estado con context

Para aplicaciones que necesitan compartir el estado de SofIA entre múltiples componentes:
import { createContext, useContext, useState, useCallback, type ReactNode } from 'react';

interface SofiaContextType {
  currentPatient: string | null;
  setCurrentPatient: (patientId: string) => void;
  reports: unknown[];
  addReport: (report: unknown) => void;
}

const SofiaContext = createContext<SofiaContextType | undefined>(undefined);

export const SofiaProvider = ({ children }: { children: ReactNode }) => {
  const [currentPatient, setCurrentPatient] = useState<string | null>(null);
  const [reports, setReports] = useState<unknown[]>([]);

  const addReport = useCallback((report: unknown) => {
    setReports((prev) => [...prev, report]);
  }, []);

  return (
    <SofiaContext.Provider value={{ currentPatient, setCurrentPatient, reports, addReport }}>
      {children}
    </SofiaContext.Provider>
  );
};

export const useSofiaContext = () => {
  const context = useContext(SofiaContext);
  if (!context) throw new Error('useSofiaContext must be used within SofiaProvider');
  return context;
};

Ejemplo completo

Para ver una implementación completa con React y TypeScript, consulte nuestro repositorio de ejemplos: Ver ejemplo completo de React El ejemplo incluye:
  • Configuración completa con Vite + React 19 + TypeScript
  • Consola de desarrollo con controles en tiempo real
  • Editores de template y datos del paciente con validación JSON
  • Cambio dinámico de User ID, Patient ID y Template ID

Mejores prácticas

Rendimiento

  • Use useCallback para callbacks estables (handleReport, setGetLastReport)
  • Implemente lazy loading para el componente en rutas no críticas

Estado

  • Pase setIsOpen directamente — el SDK controla la visibilidad
  • Cambiar userid o patientid remonta el SDK automáticamente

Error boundaries

import { Component, type ReactNode, type ErrorInfo } from 'react';

class SofiaErrorBoundary extends Component<
  { children: ReactNode },
  { hasError: boolean }
> {
  constructor(props: { children: ReactNode }) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    console.error('Error in SofIA SDK:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return <div>SofIA encountered an error. Check the browser console for details.</div>;
    }
    return this.props.children;
  }
}
Para la lista completa de mensajes de error y sus pasos de resolución, consulta la Referencia de errores.
Nunca exponga su apikey en el código del cliente en producción. Use un proxy en el backend para inyectar la API key del lado del servidor. Consulte la guía de instalación para más detalles.

Próximos pasos

  1. Integración con JavaScript
  2. Integración con Angular
  3. Referencia de propiedades requeridas
  4. Referencia de propiedades opcionales