-
Notifications
You must be signed in to change notification settings - Fork 1
/
runForm.js
154 lines (135 loc) · 5.11 KB
/
runForm.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import dotenv from "dotenv";
import fs from "fs";
import path from "path";
import { createClient } from "@supabase/supabase-js";
import { SupabaseVectorStore } from "@langchain/community/vectorstores/supabase";
import { OpenAIEmbeddings } from "@langchain/openai";
import { DirectoryLoader } from "langchain/document_loaders/fs/directory";
import { JSONLoader } from "langchain/document_loaders/fs/json";
import { TextLoader } from "langchain/document_loaders/fs/text";
import { CSVLoader } from "langchain/document_loaders/fs/csv";
import { PDFLoader } from "langchain/document_loaders/fs/pdf";
import { DocxLoader } from "langchain/document_loaders/fs/docx";
import { OpenAI } from "@langchain/openai";
import { BufferWindowMemory } from "langchain/memory";
import { RetrievalQAChain } from "langchain/chains";
import {
ChatPromptTemplate,
MessagesPlaceholder,
} from "@langchain/core/prompts";
import {
RunnableSequence,
RunnablePassthrough,
} from "@langchain/core/runnables";
import { StringOutputParser } from "@langchain/core/output_parsers";
import { formatDocumentsAsString } from "langchain/util/document";
import { HumanMessage, AIMessage } from "@langchain/core/messages";
dotenv.config();
const __dirname = path.resolve();
const privateKey = process.env.SUPABASE_PRIVATE_KEY;
const url = process.env.SUPABASE_URL;
const openaiApiKey = process.env.OPENAI_API_KEY;
if (!privateKey || !url || !openaiApiKey) {
throw new Error("Required environment variables are not set.");
}
const client = createClient(url, privateKey);
const memory = new BufferWindowMemory({
returnMessages: true,
memoryKey: "chat_history",
k: 1,
});
const loadDocuments = async (directoryPath) => {
console.log("Attempting to load documents from:", directoryPath);
if (!fs.existsSync(directoryPath)) {
console.error(`Directory does not exist: ${directoryPath}`);
return [];
}
const loader = new DirectoryLoader(directoryPath, {
".json": (path) => new JSONLoader(path),
".txt": (path) => new TextLoader(path),
".csv": (path) => new CSVLoader(path),
".pdf": (path) => new PDFLoader(path),
".docx": (path) => new DocxLoader(path),
});
try {
const documents = await loader.load();
console.log(`Loaded ${documents.length} documents.`);
return documents;
} catch (error) {
console.error("Failed to load documents:", error);
throw error;
}
};
const model = new OpenAI({
modelName: "gpt-3.5-turbo",
temperature: 1,
maxTokens: 1000,
});
const systemPrompt = `You are Nexa, a friendly chatbot designed for personalized career counseling. Your goal is to assist users in making informed decisions about their future career paths based on their individual profiles. You specialize in providing advice to students in Pakistan transitioning from 10th grade/school/O-levels to Intermediate/A-levels or from 12th grade/college/Inter to university/bachelor's degree/associate degree/diploma.
You will get name, academicStatus, percentageCgpa, fieldProgram, and interests based on user data. Suggest the best colleges or universities to the user and give the response in the form of a report like JSON object. Always provide the response in the following JSON format:
{{
"Name": "user name",
"Academic Status": "Academic Status",
"Percentage/CGPA": "Percentage/CGPA",
"Field/Program of Interest": "Field/Program of Interest",
"Interests": "Interests",
"Recommended Colleges or Universities": {{
"1.": "College/University 1",
"2.": "College/University 2",
"3.": "College/University 3",
"4.": "College/University 4"
}}
}}
Always answer the user's questions based on the below context:
{context}`;
export const runform = async (query, chatType) => {
const dataPath = path.resolve(__dirname, "./data");
const docs = await loadDocuments(dataPath);
if (!docs.length) {
console.log("No documents to process.");
return;
}
const vectorStore = new SupabaseVectorStore(new OpenAIEmbeddings(), {
client,
tableName: "documents",
queryName: "match_documents",
});
console.log("Searching for similar documents...");
const prompt = ChatPromptTemplate.fromMessages([
["system", systemPrompt],
new MessagesPlaceholder("chat_history"),
["human", "{query}"],
]);
var context;
try {
//const searchResults = await vectorStore.similaritySearch(query, 1);
const chain = RunnableSequence.from([
RunnablePassthrough.assign({
context: async (input) => {
if ("chat_history" in input && input.chat_history.length > 0) {
context = await vectorStore.similaritySearch(query, 1);
return formatDocumentsAsString(context);
}
return "";
},
}),
prompt,
model,
new StringOutputParser(),
]);
let chat_history = [];
console.log("Querying chain...");
const res = await chain.invoke({
query: query,
chat_history,
context,
});
chat_history.push(new HumanMessage(query));
chat_history.push(new AIMessage(res));
console.log("Querying chain Finished...");
console.log({ res });
return res;
} catch (error) {
console.error("Search failed:", error);
}
};