diff --git a/prisma/migrations/20240220044932_init/migration.sql b/prisma/migrations/20240220044932_init/migration.sql new file mode 100644 index 0000000..812fc70 --- /dev/null +++ b/prisma/migrations/20240220044932_init/migration.sql @@ -0,0 +1,2 @@ +-- DropIndex +DROP INDEX "conversation_userId_flowId_key"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 1dd7fa3..7835874 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -13,7 +13,7 @@ datasource db { } model conversation { - id String @default(uuid()) @db.Uuid + id String @db.Uuid createdAt DateTime @default(now()) @db.Timestamptz(3) updatedAt DateTime @updatedAt userId String @db.Uuid @@ -22,7 +22,6 @@ model conversation { flowId String feedback feedback? @@unique([id]) - @@unique([userId,flowId]) } model User { diff --git a/src/app.controller.ts b/src/app.controller.ts index 06e39e2..03d4394 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -85,13 +85,21 @@ export class AppController { let startTime = Date.now() //get userId from headers const userId = headers["user-id"] + const sessionId = headers["session-id"] console.log("userId =",userId) + console.log("sessionId =", sessionId) if(!userId){ return { "text":"", "error": "'user-id' should not be empty" } } + if(!sessionId) { + return { + "text": "", + "error": "'session-id' should not be empty" + } + } let messageType = 'intermediate_response' //setup loggers let verboseLogger = this.logger.logWithCustomFields({ @@ -152,16 +160,40 @@ export class AppController { } }) } - let conversation = await this.conversationService.getConversationState( - userId, - configid - ) + //input setup let prompt: Prompt = { input: promptDto } let userInput = promptDto.text; let type = "text" + + let defaultContext = { + sessionId, + userId, + userQuestion:'', + query: '', + queryType: '', + response: '', + userAadhaarNumber: user.identifier && configid=='3' ? user.identifier : '', + otp: '', + error: '', + currentState: "getUserQuestion", + type: '', + inputType: type, + inputLanguage: prompt.inputLanguage, + lastAadhaarDigits:'', + state:'onGoing', + isOTPVerified: false + } + + let conversation = await this.conversationService.getConversationState( + sessionId, + userId, + defaultContext, + configid + ) + //handle text and audio if(promptDto.text){ type = "Text" @@ -342,6 +374,8 @@ export class AppController { } } + conversation.inputType = type; + //get flow let botFlowMachine; switch(configid){ @@ -358,23 +392,7 @@ export class AppController { botFlowMachine = this.promptService.getXstateMachine("botFlowMachine3") } - let defaultContext = { - userId, - userQuestion:'', - query: '', - queryType: '', - response: '', - userAadhaarNumber: user.identifier && configid=='3' ? user.identifier : '', - otp: '', - error: '', - currentState: "getUserQuestion", - type: '', - inputType: type, - inputLanguage: prompt.inputLanguage, - lastAadhaarDigits:'', - state:'onGoing', - isOTPVerified: false - } + let botFlowService = interpret(botFlowMachine.withContext(conversation || defaultContext)).start(); // verboseLogger("current state when API hit =", botFlowService.state.context.currentState) @@ -1085,6 +1103,7 @@ export class AppController { } conversation = await this.conversationService.saveConversation( + sessionId, userId, botFlowService.getSnapshot().context, botFlowService.state.context.state, diff --git a/src/modules/aiTools/ai-tools.service.ts b/src/modules/aiTools/ai-tools.service.ts index 332fdd0..7e2f303 100644 --- a/src/modules/aiTools/ai-tools.service.ts +++ b/src/modules/aiTools/ai-tools.service.ts @@ -81,6 +81,11 @@ export class AiToolsService { text: string ) { try { + const urlRegex = /(https?:\/\/[^\s]+)|(www\.[^\s]+)/g; + const urls = text.match(urlRegex) || []; + + const placeHolder = "9kBjf325" //placeholder which stays the same across languages after translation + const textWithoutUrls = text.replace(urlRegex, placeHolder) let config = { "language": { "sourceLanguage": source, @@ -89,7 +94,7 @@ export class AiToolsService { } let bhashiniConfig: any = await this.getBhashiniConfig('translation',config) - let textArray = text.split("\n") + let textArray = textWithoutUrls.split("\n") for(let i=0;i urls.shift() || ''); return { - text: textArray.join('\n'), + text: translatedText, error: null } } catch(error){ @@ -254,18 +260,18 @@ export class AiToolsService { } } - async getResponseViaWadhwani(text: string) { + async getResponseViaWadhwani(sessionId: string, userId: string, text: string) { try{ var myHeaders = new Headers(); myHeaders.append("accept", "application/json"); myHeaders.append("X-API-Key", this.configService.get("WADHWANI_API_KEY")); - let response: any = await fetch(`${this.configService.get("WADHWANI_BASE_URL")}/get_bot_response?query=${text}`, { + let response: any = await fetch(`${this.configService.get("WADHWANI_BASE_URL")}/get_bot_response?query=${text}&user_id=${userId}&session_id=${sessionId}`, { headers: myHeaders, "method": "GET", "mode": "cors", "credentials": "omit" }); - response = (await response.text()).replace(/^\"|\"$/g, '') + response = await response.json() return response } catch(error){ console.log(error) diff --git a/src/modules/conversation/conversation.service.ts b/src/modules/conversation/conversation.service.ts index 56bcb58..4fb8107 100644 --- a/src/modules/conversation/conversation.service.ts +++ b/src/modules/conversation/conversation.service.ts @@ -16,14 +16,16 @@ export class ConversationService { } async saveConversation( + sessionId: string, userId: string, context: any, state: string, flowId: string ): Promise { return await this.prisma.conversation.upsert({ - where: { userId_flowId: {userId, flowId} }, + where: { id: sessionId }, create: { + id: sessionId, userId, context, state, @@ -34,20 +36,41 @@ export class ConversationService { } async getConversationState( + sessionId: string, userId: string, - flowId: string + defaultContext: any, + flowId: string, ): Promise { - const conversation: any = await this.prisma.conversation.findFirst({ + let conversation: any = await this.prisma.conversation.findFirst({ where: { - userId, - flowId, - state: 'onGoing' + id: sessionId }, }); + + if(!conversation) { + conversation = await this.prisma.conversation.create({ + data: { + id: sessionId, + userId, + context: defaultContext, + flowId, + state: 'onGoing' + } + }) + } return conversation?.context ? {...conversation.context, id:conversation.id} : null; } + async getConversationById(sessionId: string): Promise { + const conversation: any = await this.prisma.conversation.findFirst({ + where: { + id: sessionId + } + }); + return conversation?.id ? conversation : null; + } + async createOrUpdateFeedback( feedback: any ): Promise { diff --git a/src/xstate/prompt/prompt.gaurds.ts b/src/xstate/prompt/prompt.gaurds.ts index b316c00..8607c5d 100644 --- a/src/xstate/prompt/prompt.gaurds.ts +++ b/src/xstate/prompt/prompt.gaurds.ts @@ -20,8 +20,8 @@ export const promptGuards = { ifOTPHasBeenVerified: (context,_) => context.isOTPVerified, - ifInvalidClassifier: (_,event) => event.data == "invalid", + ifInvalidClassifier: (_,event) => event.data.class == "invalid", - ifConvoStarterOrEnder: (_,event) => event.data == "convo" + ifConvoStarterOrEnder: (_,event) => event.data.class == "convo" } \ No newline at end of file diff --git a/src/xstate/prompt/prompt.machine.ts b/src/xstate/prompt/prompt.machine.ts index 0477607..76a173c 100644 --- a/src/xstate/prompt/prompt.machine.ts +++ b/src/xstate/prompt/prompt.machine.ts @@ -878,19 +878,21 @@ export const botFlowMachine3:any = onDone: [ { cond: "ifConvoStarterOrEnder", - target: "wadhwaniClassifier", + target: "endFlow", actions: [ assign({ queryType: (_,event) => event.data, + response: (_,event) => event.data.response, isWadhwaniResponse: "true" }) ] }, { cond: "ifInvalidClassifier", - target: "wadhwaniClassifier", + target: "endFlow", actions: [ assign({ + response: (_,event) => event.data.response, isWadhwaniResponse: "true" }) ] diff --git a/src/xstate/prompt/prompt.service.ts b/src/xstate/prompt/prompt.service.ts index 5d0e8aa..12db8d1 100644 --- a/src/xstate/prompt/prompt.service.ts +++ b/src/xstate/prompt/prompt.service.ts @@ -34,14 +34,18 @@ export class PromptServices { async questionClassifier (context) { try{ - let response: any = await this.aiToolsService.textClassification(context.query) + let response: any = await this.aiToolsService.getResponseViaWadhwani(context.sessionId, context.userId, context.query) if (response.error) throw new Error(`${response.error}, please try again.`) if (response == `"Invalid"`) return "convo" if (response == `"convo_starter"`) return "convo" if (response == `"convo_ender"`) return "convo" if (response == `"Installment Not Received"`) return "payment" else { - return "invalid" + intent = "invalid" + } + return { + class: intent, + response: response.response } } catch (error){ return Promise.reject(error) @@ -198,7 +202,7 @@ export class PromptServices { async wadhwaniClassifier (context) { try{ - let response: any = await this.aiToolsService.getResponseViaWadhwani(context.query) + let response: any = await this.aiToolsService.getResponseViaWadhwani(context.sessionId, context.userId,context.query) if (response.error) throw new Error(`${response.error}, please try again.`) return response; } catch (error){