demoaugnitoambientsdk
Version:
Use this typescript SDK to integrate Augnito’s Ambient Tech within your EMR. To get access credentials or know more about how Augnito Ambient can benefit you, please visit our website and connect with our sales team: https://augnito.ai/
253 lines (227 loc) • 8.95 kB
text/typescript
import AmbientConfig from "./config/AmbientConfig";
import { socketConfig } from "./config/socketConfig";
import { AmbientRestAPI } from "./api/AmbientRestAPI";
import { Logger } from "./utils/Logger";
import { Guard } from "./utils/Guard";
import { AugnitoRecorder } from "demoaugnitorecorder";
import { AugnitoSocketResponse } from "./support/AugnitoSocketResponse";
/**
* Augnito Ambient Manager
* @description Handles the connection with the Ambient API Server.
*/
export class AugnitoAmbient {
private _logTag = "Augnito-Ambient";
private _ambientRestAPI: AmbientRestAPI;
private config: socketConfig | null | undefined;
private recorderIns: AugnitoRecorder | undefined;
constructor(config: AmbientConfig) {
this._ambientRestAPI = new AmbientRestAPI(this.validateConfig(config));
this.config = this.createSocketConfig(this.validateConfig(config));
}
/**
* @description Callback to receive the JOb Id
*/
public onJobCreated?: (text: string) => void;
/**
* @description Callback for status changed
*/
public onStateChanged?: (isRecording: boolean) => void;
/**
* Callback triggered when an error occurs within the SDK
*/
public onError?: (errorMessage: string) => void;
public onOtherResult?: (text: string) => void;
public onIdleMic?: () => void;
private initRecorder(_filetype: string, _noteparams: string) {
console.log(_filetype, _noteparams);
this.recorderIns = new AugnitoRecorder({
// "{\"Region\": 801, \"Specialty\": 200, \"NoteType\": 40, \"Gender\": 0}"
serverURL: this.config?.prepareWSSURL(_filetype, _noteparams) || "",
enableLogs: true,
isDebug: false,
bufferInterval: 30,
EOS_Message: "AMBIENTSDKEOS",
socketTimeoutInterval: 10000,
});
this.recorderIns.onError = this.onErrorCallback.bind(this);
this.recorderIns.onStateChanged = this.onStateChangeCallback.bind(this);
this.recorderIns.onSessionEvent =
this.onSessionEventCallback.bind(this);
this.recorderIns.onOtherResults =
this.onOtherResultsCallback.bind(this);
}
// #region Public Methods
/**
* Returns the Note parameters which need be use while doing toggle listeing
* @returns JSON object of Note parameters
*/
public async getNoteParams(): Promise<any> {
try {
if (!this._ambientRestAPI) {
Logger.error("SDK not initialized", this._logTag);
return;
}
return await this._ambientRestAPI.GetNoteParams();
} catch (e: any) {
if (e instanceof Error) {
this.onErrorCallback(e.message);
}
}
}
/**
* @param JobId to retrieve output for a specific audio file
* @returns JSON object contains both Transcript and Note on sucess else fail resonse
*/
public async getSummarizedNote(JobId: string): Promise<any> {
try {
if (!this._ambientRestAPI) {
Logger.error("SDK not initialized", this._logTag);
return;
}
var responseJson = await this._ambientRestAPI.FetchJob(JobId);
if (responseJson) {
if (responseJson.Status === 200) {
return responseJson;
} else {
this.onErrorCallback(responseJson.ErrorMessage);
}
} else {
this.onErrorCallback("Unknown Error!");
}
} catch (e: any) {
if (e instanceof Error) {
this.onErrorCallback(e.message);
}
}
}
/**
* @param JobId needs to pass to store the final Note for that audio
* @param NoteDate This key will store the final edited Note that user wants to send.
* @returns suceess response on successful submit of note else fail response
*/
public async sendSummarizedNote(
JobId: string,
NoteDate: string
): Promise<any> {
try {
if (!this._ambientRestAPI) {
Logger.error("SDK not initialized", this._logTag);
return;
}
return await this._ambientRestAPI.SendFinalNote(JobId, NoteDate);
} catch (e: any) {
if (e instanceof Error) {
this.onErrorCallback(e.message);
}
}
}
/**
* @param filetype Type of file being uploaded, wav, mp3, etc. Ex: “filetype=wav“
* @param noteparams Qualifiers to determine the type of clinical note to be generated for that audio file.
* @returns Callback triggers to reurn the Job id on meta message
*/
public toggleListening(_filetype: string, _noteparams: string): void {
console.log("toggleListening:", _filetype, _noteparams);
if (!this.recorderIns) {
this.initRecorder(_filetype, _noteparams);
}
this.recorderIns?.toggleStartStopAudioStream();
}
// #endregion
// #region client callbacks
private onEventCallback(data: string): void {
if (this.onJobCreated) {
this.onJobCreated(data);
}
}
private onStateChangeCallback(isRecording: boolean): void {
if (this.onStateChanged) {
this.onStateChanged(isRecording);
}
}
private onErrorCallback(errorMessage: string): void {
if (this.onError) {
this.onError(errorMessage);
}
}
private onOtherResultsCallback(data: string): void {
if (this.onOtherResult) {
this.onOtherResult(data);
}
}
private onIdleMicCallback(): void {
if (this.onIdleMic) {
this.onIdleMic();
}
}
private onSessionEventCallback(data: string | AugnitoSocketResponse): void {
if (!data) {
return;
}
let json: any;
try {
json = typeof data === "string" ? JSON.parse(data) : data;
} catch (error) {
Logger.error(
`Error parsing session event data: ${error}`,
this._logTag
);
return;
}
if (!json || !("Type" in json)) {
return;
}
if (json.Type.toLowerCase() === "meta" && this.config?.onMetaEvent) {
if (!json.JobID) {
Logger.error(`JobID is missing in meta event`, this._logTag);
return;
}
this.config.onMetaEvent(json.JobID);
} else if (json.Type.toLowerCase() === "error" && json.Data) {
this.onErrorCallback(json.Data);
}
if (typeof json.Event !== "object" || json.Event === null) {
return;
}
const { Type: eventType, Value: eventValue } = json.Event;
if (!eventType) {
return;
}
if (eventType === "SESSION_CREATED" && eventValue) {
Logger.log(`session Token ${eventValue}`, this._logTag);
} else if (eventType === "SERVICE_DOWN") {
Logger.error(eventType, this._logTag);
} else if (eventType === "NO_DICTATION_STOP_MIC") {
Logger.log("NO_DICTATION_STOP_MIC", this._logTag);
this.onIdleMicCallback();
} else if (eventType === "INVALID_AUTH_CREDENTIALS") {
Logger.error("INVALID_AUTH_CREDENTIALS", this._logTag);
} else if (eventType === "LOW_BANDWIDTH") {
Logger.log(
"LOW_BANDWIDTH: Check internet connection",
this._logTag
);
}
}
// #endregion
/**
* Validates the Ambient config has all the mandatory fields
* @param config The config sent by the client application
*/
validateConfig(config: AmbientConfig): AmbientConfig {
Guard.Against.NullOrEmpty(config.server, "Server");
Guard.Against.NullOrEmpty(config.subscriptionCode, "SubscriptionCode");
Guard.Against.NullOrEmpty(config.accessKey, "AccessKey");
Guard.Against.NullOrEmpty(config.userTag, "UserTag");
return config;
}
private createSocketConfig(config: AmbientConfig): socketConfig {
const _socketConfig = new socketConfig(config);
// _socketConfig.onStartOfRecording =
// this.onStateChangeCallback.bind(this);
// _socketConfig.onStopOfRecording = this.onStateChangeCallback.bind(this);
_socketConfig.onError = this.onErrorCallback.bind(this);
_socketConfig.onMetaEvent = this.onEventCallback.bind(this);
return _socketConfig;
}
}