Saltar al contenido principal
Esta guía muestra cómo integrar SofIA SDK en aplicaciones React, aprovechando el soporte nativo para Web Components.

Configuración inicial

1. Instalación

npm install @omniloy/sofia-sdk

2. Importación en su aplicación

// En su App.tsx o archivo principal
import '@omniloy/sofia-sdk';

Componente React básico

Implementación con hooks

import React, { useRef, useState, useEffect } from 'react';

interface SofiaComponentProps {
  userId: string;
  patientId: string;
  apiKey: string;
  baseUrl: string;
  wssUrl: string;
}

const SofiaComponent: React.FC<SofiaComponentProps> = ({
  userId,
  patientId,
  apiKey,
  baseUrl,
  wssUrl
}) => {
  const sofiaRef = useRef<any>(null);
  const [isOpen, setIsOpen] = useState(false);
  const [lastReport, setLastReport] = useState<any>(null);

  // Esquema de ejemplo para notas clínicas
  const toolsArgs = {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "clinical_notes",
    "type": "object",
    "required": ["diagnosis"],
    "properties": {
      "diagnosis": {
        "type": "string",
        "description": "Diagnóstico principal"
      },
      "symptoms": {
        "type": "array",
        "items": {"type": "string"},
        "description": "Síntomas observados"
      }
    }
  };

  // Configurar callbacks cuando el componente se monta
  useEffect(() => {
    if (sofiaRef.current) {
      // Callback para recibir reportes
      sofiaRef.current.handleReport = (report: any) => {
        console.log('Reporte recibido:', report);
        setLastReport(report);
        
        // Procesar reporte (enviar a API, mostrar notificación, etc.)
        processReport(report);
      };

      // Callback para cambios de visibilidad
      sofiaRef.current.setIsOpen = (open: boolean) => {
        setIsOpen(open);
      };
    }
  }, []);

  const processReport = async (report: any) => {
    try {
      // Enviar reporte a su backend
      const response = await fetch('/api/clinical-reports', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(report)
      });
      
      if (response.ok) {
        console.log('Reporte guardado exitosamente');
      }
    } catch (error) {
      console.error('Error procesando reporte:', error);
    }
  };

  const toggleSofia = () => {
    if (sofiaRef.current) {
      sofiaRef.current.isopen = !isOpen;
    }
  };

  return (
    <div className="sofia-container">
      <sofia-sdk
        ref={sofiaRef}
        baseurl={baseUrl}
        wssurl={wssUrl}
        apikey={apiKey}
        userid={userId}
        patientid={patientId}
        isopen={isOpen.toString()}
        toolsargs={JSON.stringify(toolsArgs)}
      />
      
      <div className="sofia-controls">
        <button onClick={toggleSofia} className="toggle-button">
          {isOpen ? 'Cerrar SofIA' : 'Abrir SofIA'}
        </button>
        
        {lastReport && (
          <div className="last-report">
            <h3>Último reporte:</h3>
            <pre>{JSON.stringify(lastReport, null, 2)}</pre>
          </div>
        )}
      </div>
    </div>
  );
};

export default SofiaComponent;

Hook personalizado

useSofia Hook

import { useRef, useState, useCallback } from 'react';

interface UseSofiaOptions {
  onReport?: (report: any) => void;
  onVisibilityChange?: (isOpen: boolean) => void;
}

export const useSofia = (options: UseSofiaOptions = {}) => {
  const sofiaRef = useRef<any>(null);
  const [isOpen, setIsOpen] = useState(false);
  const [isLoading, setIsLoading] = useState(false);

  const initializeSofia = useCallback(() => {
    if (sofiaRef.current) {
      sofiaRef.current.handleReport = (report: any) => {
        setIsLoading(false);
        options.onReport?.(report);
      };

      sofiaRef.current.setIsOpen = (open: boolean) => {
        setIsOpen(open);
        options.onVisibilityChange?.(open);
      };
    }
  }, [options]);

  const openSofia = useCallback(() => {
    if (sofiaRef.current) {
      sofiaRef.current.isopen = true;
    }
  }, []);

  const closeSofia = useCallback(() => {
    if (sofiaRef.current) {
      sofiaRef.current.isopen = false;
    }
  }, []);

  const generateReport = useCallback(() => {
    if (sofiaRef.current) {
      setIsLoading(true);
      // Triggering report generation if supported
      sofiaRef.current.dispatchEvent(new CustomEvent('generate'));
    }
  }, []);

  return {
    sofiaRef,
    isOpen,
    isLoading,
    initializeSofia,
    openSofia,
    closeSofia,
    generateReport
  };
};

Uso del hook

const MyComponent: React.FC = () => {
  const { 
    sofiaRef, 
    isOpen, 
    isLoading, 
    initializeSofia, 
    openSofia, 
    closeSofia 
  } = useSofia({
    onReport: (report) => {
      console.log('Reporte procesado:', report);
    },
    onVisibilityChange: (isOpen) => {
      console.log('Estado cambió:', isOpen);
    }
  });

  useEffect(() => {
    initializeSofia();
  }, [initializeSofia]);

  return (
    <div>
      <sofia-sdk
        ref={sofiaRef}
        baseurl="https://api.example.com/v1"
        wssurl="wss://ws.example.com"
        apikey="sk-your-api-key-here"
        userid="user_12345"
        patientid="patient_67890"
        isopen={isOpen.toString()}
        toolsargs={JSON.stringify(mySchema)}
      />
      
      <button onClick={openSofia} disabled={isOpen}>
        Abrir SofIA
      </button>
      <button onClick={closeSofia} disabled={!isOpen}>
        Cerrar SofIA
      </button>
      
      {isLoading && <div>Generando reporte...</div>}
    </div>
  );
};

Gestión de estado con Context

Sofia Context Provider

import React, { createContext, useContext, useState, ReactNode } from 'react';

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

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

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

  const addReport = (report: any) => {
    setReports(prev => [...prev, { ...report, timestamp: new Date() }]);
  };

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

TypeScript Support

Declaración de tipos

// types/sofia.d.ts
declare global {
  namespace JSX {
    interface IntrinsicElements {
      'sofia-sdk': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
        baseurl?: string;
        wssurl?: string;
        apikey?: string;
        userid?: string;
        patientid?: string;
        isopen?: string;
        toolsargs?: string;
        patientdata?: string;
        ref?: React.Ref<any>;
      };
    }
  }
}

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 TypeScript
  • Estado global con Context API
  • Componentes reutilizables
  • Integración con React Router
  • Testing con Jest y React Testing Library

Mejores prácticas

Performance

  • Use React.memo() para componentes que envuelven sofia-sdk
  • Implemente lazy loading para el componente en rutas no críticas

Estado

  • Mantenga el estado de SofIA sincronizado con el estado de React
  • Use useCallback para callbacks estables

Error Boundaries

class SofiaErrorBoundary extends React.Component {
  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error('Error en SofIA SDK:', error, errorInfo);
  }

  render() {
    return this.props.children;
  }
}