-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(api): enable webhook for whatsapp
- Loading branch information
Showing
22 changed files
with
579 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { ChatMistralAI } from "@langchain/mistralai"; | ||
import { ChatOpenAI } from "@langchain/openai"; | ||
|
||
export const models = { | ||
gpt4: (apiKey: string) => { | ||
return new ChatOpenAI({ | ||
model: "gpt-4", | ||
temperature: 0, | ||
maxRetries: 2, | ||
apiKey, | ||
}); | ||
}, | ||
mistral: (apiKey: string) => { | ||
return new ChatMistralAI({ | ||
model: "mistral-large-latest", | ||
temperature: 0, | ||
maxRetries: 2, | ||
apiKey, | ||
}); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Annotation, MessagesAnnotation } from "@langchain/langgraph"; | ||
import { MyNodes } from "./nodes"; | ||
|
||
export const GraphState = Annotation.Root({ | ||
...MessagesAnnotation.spec, | ||
lastAgent: Annotation<MyNodes>, | ||
}); | ||
|
||
export type GraphState = typeof GraphState.State; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { END, START, StateGraph } from "@langchain/langgraph"; | ||
import { MemorySaver } from "@langchain/langgraph"; | ||
|
||
import { GraphState } from "./graph.state"; | ||
|
||
import { MyNodes } from "./nodes"; | ||
import { toolNode } from "./nodes/tool.node"; | ||
import { availabilityNode } from "./nodes/availability.node"; | ||
import { bookingNode } from "./nodes/booking.node"; | ||
import { conversationalNode } from "./nodes/conversation.node"; | ||
|
||
import { checkerToolRouter } from "./routers/checkerTool.router"; | ||
import { availabilityRouter } from "./routers/availability.router"; | ||
import { toolToNodeRouter } from "./routers/toolToNode.router"; | ||
import { intentRouter } from "./routers/intent.router"; | ||
import { models } from "./getModel"; | ||
|
||
interface Props { | ||
openAIKey: string; | ||
mistralKey: string; | ||
} | ||
|
||
export const createGraph = (data: Props) => { | ||
const memory = new MemorySaver(); | ||
|
||
const llmGpt4 = models.gpt4(data.openAIKey); | ||
const llmMistral = models.mistral(data.mistralKey); | ||
|
||
const workflow = new StateGraph(GraphState) | ||
// nodes | ||
.addNode(MyNodes.TOOLS, toolNode) | ||
.addNode(MyNodes.AVAILABILITY, availabilityNode(llmGpt4)) | ||
.addNode(MyNodes.BOOKING, bookingNode(llmGpt4)) | ||
.addNode(MyNodes.CONVERSATION, conversationalNode(llmMistral)) | ||
// edges | ||
.addEdge(MyNodes.CONVERSATION, END) | ||
.addEdge(MyNodes.BOOKING, END) | ||
// routers | ||
.addConditionalEdges(MyNodes.TOOLS, toolToNodeRouter, [ | ||
MyNodes.AVAILABILITY, | ||
MyNodes.BOOKING, | ||
END, | ||
]) | ||
.addConditionalEdges(MyNodes.AVAILABILITY, availabilityRouter(llmMistral), [ | ||
MyNodes.TOOLS, | ||
MyNodes.BOOKING, | ||
END, | ||
]) | ||
.addConditionalEdges(MyNodes.BOOKING, checkerToolRouter, [ | ||
MyNodes.TOOLS, | ||
END, | ||
]) | ||
.addConditionalEdges(START, intentRouter(llmMistral), [ | ||
MyNodes.AVAILABILITY, | ||
MyNodes.BOOKING, | ||
MyNodes.CONVERSATION, | ||
]); | ||
|
||
return workflow.compile({ checkpointer: memory }); | ||
}; |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { formatDate } from "date-fns"; | ||
import { checkAvailabilityTool } from "../tools/checkAvailability.tool"; | ||
|
||
import { GraphState } from "../graph.state"; | ||
import { SystemMessage } from "@langchain/core/messages"; | ||
import { MyNodes } from "."; | ||
import { ChatOpenAI } from "@langchain/openai"; | ||
|
||
const SYSTEM_PROMPT = (formattedDate: string) => { | ||
return `You are expert assistant for checking the availability of Sander's, a hairdressing salon in Cochabamba (Bolivia). To help customers check availability for appointments, you ask them for the date they would like to book an appointment. | ||
# RULES | ||
- As reference, today is ${formattedDate}. | ||
- Don't assume parameters in call functions that it didnt say. | ||
- MUST NOT force users how to write. Let them write in the way they want. | ||
- The conversation should be very natural like a secretary talking with a client. | ||
- Call only ONE tool at a time. | ||
- Your responses must be in spanish.`; | ||
}; | ||
|
||
export const availabilityNode = (llm: ChatOpenAI) => { | ||
return async (state: GraphState) => { | ||
const { messages } = state; | ||
|
||
const formattedDate = formatDate(new Date(), "yyyy-MM-dd"); | ||
const systemPrompt = SYSTEM_PROMPT(formattedDate); | ||
llm.bindTools([checkAvailabilityTool]); | ||
|
||
let trimmedHistory = messages; | ||
if (trimmedHistory.at(-1)?.getType() === "ai") { | ||
trimmedHistory = trimmedHistory.slice(0, -1); | ||
} | ||
|
||
const response = await llm.invoke([ | ||
new SystemMessage(systemPrompt), | ||
...trimmedHistory.filter((m) => m.getType() !== "system"), | ||
]); | ||
return { messages: response, lastAgent: MyNodes.AVAILABILITY }; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { SystemMessage } from "@langchain/core/messages"; | ||
|
||
import { MyNodes } from "."; | ||
import { GraphState } from "../graph.state"; | ||
import { models } from "../getModel"; | ||
import { bookAppointmentTool } from "../tools/bookAppointment.tool"; | ||
import { ChatOpenAI } from "@langchain/openai"; | ||
|
||
const SYSTEM_PROMPT = () => { | ||
return `You are Expert Assistant for booking an appointment at Sander's, a hairdressing salon in Cochabamba (Bolivia). | ||
To book an appointment, you ask for the date and the name of the client | ||
# RULES | ||
- Recognize previously mentioned information | ||
- Do not assume parameters in calling functions that it does not say. | ||
- MUST NOT force users how to write. Let them write the way they want. | ||
- The conversation should be very natural, like a secretary talking to a client. | ||
- Only call ONE tool at a time. | ||
- Your answers must be in Spanish.`; | ||
}; | ||
|
||
export const bookingNode = (llm: ChatOpenAI) => { | ||
return async (state: GraphState) => { | ||
const { messages } = state; | ||
|
||
const systemPrompt = SYSTEM_PROMPT(); | ||
llm.bindTools([bookAppointmentTool]); | ||
|
||
let trimmedHistory = messages; | ||
if (trimmedHistory.at(-1)?.getType() === "ai") { | ||
trimmedHistory = trimmedHistory.slice(0, -1); | ||
} | ||
|
||
const response = await llm.invoke([ | ||
new SystemMessage(systemPrompt), | ||
...trimmedHistory.filter((m) => m.getType() !== "system"), | ||
]); | ||
return { | ||
messages: response, | ||
lastAgent: MyNodes.BOOKING, | ||
}; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { ChatMistralAI } from "@langchain/mistralai"; | ||
import { MyNodes } from "."; | ||
import { GraphState } from "../graph.state"; | ||
|
||
const SUPPORT_PROMPT = `You are frontline support for Sander's, a hair salon in Cochabamba (Bolivia). | ||
You can chat with customers and help them with basic questions, do not try to answer the question directly or gather information. | ||
# RULES | ||
- Be concise in your responses. | ||
- Don't assume parameters in call functions that it didnt say. | ||
- MUST NOT force users how to write. Let them write in the way they want. | ||
- The conversation should be very natural like a secretary talking with a client. | ||
- Call only ONE tool at a time. | ||
- Your responses must be in spanish. | ||
- Keep a friendly, professional tone. | ||
- Avoid verbosity. | ||
- Don't mention the name of the team you are transferring the user to. | ||
# INTRODUCE YOURSELF | ||
Hola, soy SanderBot, tu asistente virtual. ¿En qué puedo ayudarte hoy? | ||
`; | ||
|
||
export const conversationalNode = (llm: ChatMistralAI) => { | ||
return async (state: GraphState) => { | ||
const { messages } = state; | ||
const response = await llm.invoke([ | ||
{ role: "system", content: SUPPORT_PROMPT }, | ||
...messages, | ||
]); | ||
|
||
return { | ||
messages: response, | ||
lastAgent: MyNodes.CONVERSATION, | ||
}; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export enum MyNodes { | ||
CONVERSATION = "conversation", | ||
BOOKING = "booking", | ||
AVAILABILITY = "availability", | ||
TOOLS = "tools", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { ToolNode } from "@langchain/langgraph/prebuilt"; | ||
|
||
import { checkAvailabilityTool } from "../tools/checkAvailability.tool"; | ||
import { bookAppointmentTool } from "../tools/bookAppointment.tool"; | ||
|
||
export const toolNode = new ToolNode([ | ||
checkAvailabilityTool, | ||
bookAppointmentTool, | ||
]); |
Oops, something went wrong.