Initial setup
1. Installation
Copy
npm install @omniloy/sofia-sdk
2. Import in your application
Copy
// In your App.tsx or main file
import '@omniloy/sofia-sdk';
Basic React component
Implementation with hooks
Copy
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);
// Example schema for clinical notes
const toolsArgs = {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "clinical_notes",
"type": "object",
"required": ["diagnosis"],
"properties": {
"diagnosis": {
"type": "string",
"description": "Main diagnosis"
},
"symptoms": {
"type": "array",
"items": {"type": "string"},
"description": "Observed symptoms"
}
}
};
// Configure callbacks when component mounts
useEffect(() => {
if (sofiaRef.current) {
// Callback to receive reports
sofiaRef.current.handleReport = (report: any) => {
console.log('Report received:', report);
setLastReport(report);
// Process report (send to API, show notification, etc.)
processReport(report);
};
// Callback for visibility changes
sofiaRef.current.setIsOpen = (open: boolean) => {
setIsOpen(open);
};
}
}, []);
const processReport = async (report: any) => {
try {
// Send report to your backend
const response = await fetch('/api/clinical-reports', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(report)
});
if (response.ok) {
console.log('Report saved successfully');
}
} catch (error) {
console.error('Error processing report:', 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 ? 'Close SofIA' : 'Open SofIA'}
</button>
{lastReport && (
<div className="last-report">
<h3>Last report:</h3>
<pre>{JSON.stringify(lastReport, null, 2)}</pre>
</div>
)}
</div>
</div>
);
};
export default SofiaComponent;
Custom hook
useSofia Hook
Copy
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
};
};
Using the hook
Copy
const MyComponent: React.FC = () => {
const {
sofiaRef,
isOpen,
isLoading,
initializeSofia,
openSofia,
closeSofia
} = useSofia({
onReport: (report) => {
console.log('Report processed:', report);
},
onVisibilityChange: (isOpen) => {
console.log('State changed:', 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}>
Open SofIA
</button>
<button onClick={closeSofia} disabled={!isOpen}>
Close SofIA
</button>
{isLoading && <div>Generating report...</div>}
</div>
);
};
State management with Context
Sofia Context Provider
Copy
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
Type declarations
Copy
// 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>;
};
}
}
}
Complete example
For a complete implementation with React and TypeScript, check our examples repository: View complete React example → The example includes:- Complete TypeScript setup
- Global state with Context API
- Reusable components
- React Router integration
- Testing with Jest and React Testing Library
Best practices
Performance
- Use
React.memo()for components wrapping sofia-sdk - Implement lazy loading for components on non-critical routes
State
- Keep SofIA state synchronized with React state
- Use useCallback for stable callbacks
Error Boundaries
Copy
class SofiaErrorBoundary extends React.Component {
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('Error in SofIA SDK:', error, errorInfo);
}
render() {
return this.props.children;
}
}