Initial Setup
1. Package Installation
Copy
npm install @omniloy/sofia-sdk
2. Module Configuration
Angular requires specific configuration to support Web Components:Copy
// app.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
// Import SofIA SDK
import '@omniloy/sofia-sdk';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA] // Required for Web Components
})
export class AppModule { }
3. Standalone Components Configuration (Angular 14+)
For applications using Standalone Components:Copy
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import '@omniloy/sofia-sdk';
bootstrapApplication(AppComponent, {
providers: []
});
Copy
// app.component.ts
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@Component({
selector: 'app-root',
standalone: true,
templateUrl: './app.component.html',
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppComponent {
// Component implementation
}
Component Implementation
HTML Template
Copy
<!-- app.component.html -->
<sofia-sdk
baseurl="https://api.omniloy.com"
wssurl="wss://wss.omniloy.com"
apikey="PROD_KEY"
[attr.userid]="userId"
[attr.patientid]="patientId"
[attr.toolsargs]="toolsArgsJson"
[attr.isopen]="isOpen ? 'true' : 'false'"
(handle-report)="onReport($event.detail)"
(set-is-open)="onSetIsOpen($event.detail)">
</sofia-sdk>
TypeScript Component
Copy
// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
userId = 'angular-user-123';
patientId = 'patient-456';
isOpen = false;
// JSON Schema for clinical configuration
toolsArgsJson = JSON.stringify({
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Medical Consultation",
"type": "object",
"properties": {
"diagnosis": {
"type": "string",
"description": "Primary diagnosis"
},
"treatment": {
"type": "string",
"description": "Treatment plan"
}
},
"required": ["diagnosis"]
});
// Callback when a report is generated
onReport(report: any) {
console.log('Report received:', report);
// Here you can process the generated report
// For example, send it to your backend or EHR
}
// Callback when open state changes
onSetIsOpen(isOpen: boolean) {
this.isOpen = isOpen;
console.log('Open state:', isOpen);
}
// Method to open/close programmatically
toggleSofIA() {
this.isOpen = !this.isOpen;
}
}
Advanced Configuration
TypeScript Interfaces
For better typing, you can define interfaces for the data:Copy
// interfaces/sofia.interface.ts
export interface SofiaReport {
diagnosis: string;
treatment?: string;
timestamp: string;
userId: string;
patientId: string;
}
export interface PatientData {
name: string;
age: number;
gender: 'M' | 'F';
history?: string;
}
Angular Service
You can encapsulate SofIA logic in a service:Copy
// services/sofia.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { SofiaReport } from '../interfaces/sofia.interface';
@Injectable({
providedIn: 'root'
})
export class SofiaService {
private reportSubject = new BehaviorSubject<SofiaReport | null>(null);
private isOpenSubject = new BehaviorSubject<boolean>(false);
// Public observables
report$: Observable<SofiaReport | null> = this.reportSubject.asObservable();
isOpen$: Observable<boolean> = this.isOpenSubject.asObservable();
// Methods to handle reports
handleReport(report: SofiaReport) {
this.reportSubject.next(report);
// Here you can add additional logic like saving to localStorage
// or sending to server
}
// Methods to handle state
setIsOpen(isOpen: boolean) {
this.isOpenSubject.next(isOpen);
}
// Method to generate toolsArgs dynamically
generateToolsArgs(specialty: string): string {
const baseSchema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": `${specialty} Consultation`,
"type": "object"
};
// Customize by specialty
switch(specialty) {
case 'cardiology':
return JSON.stringify({
...baseSchema,
"properties": {
"diagnosis": { "type": "string" },
"heart_rate": { "type": "number" },
"blood_pressure": { "type": "string" }
}
});
case 'dermatology':
return JSON.stringify({
...baseSchema,
"properties": {
"diagnosis": { "type": "string" },
"lesion_type": { "type": "string" },
"location": { "type": "string" }
}
});
default:
return JSON.stringify({
...baseSchema,
"properties": {
"diagnosis": { "type": "string" },
"treatment": { "type": "string" }
}
});
}
}
}
Using the service in component
Copy
// app.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { SofiaService } from './services/sofia.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
userId = 'angular-user-123';
patientId = 'patient-456';
isOpen = false;
toolsArgsJson = '';
constructor(private sofiaService: SofiaService) {}
ngOnInit() {
// Subscribe to state changes
this.sofiaService.isOpen$
.pipe(takeUntil(this.destroy$))
.subscribe(isOpen => {
this.isOpen = isOpen;
});
// Subscribe to reports
this.sofiaService.report$
.pipe(takeUntil(this.destroy$))
.subscribe(report => {
if (report) {
console.log('New report:', report);
// Process report
}
});
// Configure initial toolsArgs
this.toolsArgsJson = this.sofiaService.generateToolsArgs('general');
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
onReport(report: any) {
this.sofiaService.handleReport(report);
}
onSetIsOpen(isOpen: boolean) {
this.sofiaService.setIsOpen(isOpen);
}
}
Important Considerations
Change Detection
Angular may require manual change detection in some cases:Copy
import { ChangeDetectorRef } from '@angular/core';
constructor(private cdr: ChangeDetectorRef) {}
onReport(report: any) {
// Process report
this.cdr.detectChanges(); // Force detection if necessary
}
Component Lifecycle
Copy
ngAfterViewInit() {
// Web Component is available after view initialization
const sofiaElement = document.querySelector('sofia-sdk');
if (sofiaElement) {
// Additional configuration if necessary
}
}
Error Handling
Copy
onReport(report: any) {
try {
// Process report
this.processReport(report);
} catch (error) {
console.error('Error processing report:', error);
// Handle error appropriately
}
}
Integration with Angular Material
If you use Angular Material, you can integrate SofIA with its components:Copy
<mat-card>
<mat-card-header>
<mat-card-title>Medical Consultation</mat-card-title>
<mat-card-subtitle>Patient: {{patientId}}</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<sofia-sdk
[attr.apikey]="apiKey"
[attr.userid]="userId"
[attr.patientid]="patientId"
[attr.toolsargs]="toolsArgsJson"
[attr.isopen]="isOpen ? 'true' : 'false'"
(handle-report)="onReport($event.detail)"
(set-is-open)="onSetIsOpen($event.detail)">
</sofia-sdk>
</mat-card-content>
<mat-card-actions>
<button mat-button (click)="toggleSofIA()">
{{isOpen ? 'Close' : 'Open'}} SofIA
</button>
</mat-card-actions>
</mat-card>