/* eslint-disable */
import { Inject, Injectable, Headers, InternalServerErrorException, BadRequestException } from '@nestjs/common';
import { AxiosUtil, LOGGER, LoggerUtil } from '@cvsdigital_sdk/nest-graphql-common';
import { ConfigService } from '@nestjs/config';
import CacheUtil from './utils/cache.util';
import MasterIntentClassifierResponse from './model/masterintent.model';
import IntentClassEnum from './model/intentClass.enum';
import { IntentRule, IntentRules } from './model/intent-rules.interface';
import { MatchedIntentResponse } from './model/matched-intent-response.model';
import DigitalIVRSessionsEntity from './entity/DigitalIVRSessions.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import PrescriberAddress from './masterintent.repository';
import IntentExperienceService from './intent.experience.service';
import { performance } from 'perf_hooks';
@Injectable()
export default class MasterIntentService {
private configPrefix: string;
constructor(
private axiosUtil: AxiosUtil,
private readonly configService: ConfigService,
private readonly cacheUtil: CacheUtil,
private readonly experienceService: IntentExperienceService,
@InjectRepository(DigitalIVRSessionsEntity)
private digitalIVRSessionsEntity: Repository<DigitalIVRSessionsEntity>,
@Inject(LOGGER) private readonly logger: LoggerUtil,
) {}
public setConfigPrefix(channel: string | string[]): void {
let prefix: string;
if (Array.isArray(channel)) {
prefix = channel[0];
} else {
prefix = channel;
}
if (prefix !== 'X42_IVR' && prefix !== 'X42_CHAT') {
prefix = 'X42_IVR';
}
this.configPrefix = prefix;
}
/**
* Get Master Intent
* @param userText
* @param channel
* @param id
* @param idType
*/
public async getMasterIntent(userText: string, id?: string, idType?: string, store?: string): Promise<any> {
const startTime = performance.now();
const masterIntentResponse: MasterIntentClassifierResponse = new MasterIntentClassifierResponse();
masterIntentResponse.statusFlags = {
expeditedPrescriptionEligibleCount: -1,
prescriptionEligibleCount: -1,
cancelPrescriptionEligibleCount: -1,
refillablePrescriptionEligibleCount: -1,
transferPrescriptionEligibleCount: -1,
prescriptionStatus: [],
};
// Classify intent and skip words in parallel
const mlResponsePromise = this.classifyIntent(userText);
const skipWordsPromise = this.configService.get<string[]>(`skipWords`) || [];
const cacheLogicPromise = id && idType ? this.handleCacheLogic(masterIntentResponse, id, idType) : Promise.resolve();
const userQueryCache = this.getUserQueryCache(userText, masterIntentResponse);
const [mlResponse, skipWords, cacheLogicResponse, userCacheResponse] = await Promise.all([
mlResponsePromise,
skipWordsPromise,
cacheLogicPromise,
userQueryCache,
]);
// Process high-level intent and check if it should be skipped
const highLevelIntent = mlResponse?.intents.length ? mlResponse.intents[0].toLowerCase().trim() : 'unknown';
const isSkip = skipWords.some((word) => highLevelIntent.toLowerCase().includes(word.toLowerCase()));
let intentResp: string[] | undefined;
// Get Intent AI data if not skipping and cache is not available
if (highLevelIntent !== 'unknown' && !isSkip && !userCacheResponse) {
const intentAIDataPromise = this.getIntentAIData(userText, highLevelIntent);
const response = await intentAIDataPromise;
intentResp = response?.chat_response.split(',');
masterIntentResponse.subIntent = intentResp.map((i: string) => i.toLowerCase().trim());
} else {
masterIntentResponse.subIntent = userCacheResponse ? [userCacheResponse] : [highLevelIntent];
}
masterIntentResponse.userText = userText;
// Filter out 'help' from subIntents if necessary
const valueToRemove = 'help';
masterIntentResponse.subIntent =
masterIntentResponse.subIntent.length > 1
? masterIntentResponse.subIntent.filter((item) => item !== valueToRemove)
: masterIntentResponse.subIntent;
await cacheLogicPromise;
// Handle intent matching
let matchedIntent: MatchedIntentResponse = await this.matchIntent(masterIntentResponse.subIntent);
if (masterIntentResponse.subIntent.includes('unknown')) {
masterIntentResponse.intent = String(IntentClassEnum.INTENT_UNKNOWN);
} else if (matchedIntent.matchedAttributes.mainIntent === 'multiintent') {
matchedIntent = await this.matchExceptionIntent(masterIntentResponse.subIntent);
}
masterIntentResponse.intent = matchedIntent.matchedAttributes.mainIntent;
masterIntentResponse.fillerText = matchedIntent.partialFiller;
masterIntentResponse.promptId = matchedIntent.matchedAttributes.promptID?.trim() || '-1';
masterIntentResponse.templateId = matchedIntent.matchedAttributes.dataTemplate?.trim() || '-1';
masterIntentResponse.ruleNo = matchedIntent.matchedAttributes.ruleNo?.trim() || '-1';
masterIntentResponse.seqNo = matchedIntent.matchedAttributes.seqNo;
// Additional check for patient interaction
let patientInteractedRecently = false;
masterIntentResponse.statusFlags.patientInteractedRecently = patientInteractedRecently;
if (masterIntentResponse.intent === 'live_pharmacist' && id) {
patientInteractedRecently = await this.hasRecentEntry(id);
masterIntentResponse.statusFlags.patientInteractedRecently = patientInteractedRecently;
this.logger.addFunctionalTags(
'masterIntentResponse.patientInteractedRecently',
`${patientInteractedRecently}`,
);
}
// Call classifyIntentForPartialFiller and set fillerText
const partialFillerResponse = await this.classifyIntentForPartialFiller(userText, highLevelIntent);
masterIntentResponse.fillerText = partialFillerResponse?.text || '';
// Log response and performance
this.logger.addFunctionalTags('masterIntentResponse.intent', `${masterIntentResponse.intent}`);
this.logger.addFunctionalTags('masterIntentResponse.subIntent', `${masterIntentResponse.subIntent}`);
this.logger.addFunctionalTags('masterIntentResponse.fillerText', `${masterIntentResponse.fillerText}`);
this.logger.addFunctionalTags('masterIntentResponse.promptId', `${masterIntentResponse.promptId}`);
this.logger.addFunctionalTags('masterIntentResponse.templateId', `${masterIntentResponse.templateId}`);
this.logger.addFunctionalTags('masterIntentResponse.ruleId', `${matchedIntent.matchedAttributes.ruleNo}`);
this.logger.addFunctionalTags('masterIntentResponse.seqNo', `${matchedIntent.matchedAttributes.seqNo}`);
this.logger.addFunctionalTags('masterIntentResponse', `${JSON.stringify(masterIntentResponse)}`);
const endTime = performance.now();
const duration = endTime - startTime;
this.logger.addFunctionalTags('MasterIntentServiceTimeTaken', `${duration}ms`);
return masterIntentResponse;
}
/**
* Classify Intent for Partial Filler
* @param userText
* @param highLevelIntent
* @returns Partial filler text response
*/
private async classifyIntentForPartialFiller(userText: string, highLevelIntent: string): Promise<any> {
const classifyIntentReq: any = {
query: userText,
intent: highLevelIntent,
};
this.logger.addFunctionalTags('classifyIntentForPartialFillerRequest', classifyIntentReq);
// Extract the client name directly without including the configPrefix
const clientName = `${this.configPrefix}.ClassifyIntentForPartialFiller`;
// Use the configPrefix to correctly fetch the URI
const uri = this.configService.get<string>(`client.${clientName}.uri`);
this.logger.addFunctionalTags('configUriForPartialFiller', uri);
const startTime = performance.now();
const classifyIntentForPartialFillerResponse: any = await this.axiosUtil.getInstance(clientName).post(uri, classifyIntentReq);
const endTime = performance.now();
const duration = endTime - startTime;
this.logger.addFunctionalTags('classifyIntentForPartialFillerTimeTaken', `${duration}ms`);
this.logger.addFunctionalTags('classifyIntentForPartialFillerResponse', classifyIntentForPartialFillerResponse);
return classifyIntentForPartialFillerResponse;
}
// Other existing methods ...
}