112211

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